diff options
author | Revanshu Paliwal <revanshu.paliwal@sonarsource.com> | 2022-11-17 15:59:16 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-11-22 20:03:04 +0000 |
commit | 9d2a38de3347dc85890fae454f82154a52267a69 (patch) | |
tree | c113ef64cea2bfe1f2f2b0734643faf7abc45f3a /server/sonar-web | |
parent | 4d779c10b3e45cb2ea734af9cfa235690f68916a (diff) | |
download | sonarqube-9d2a38de3347dc85890fae454f82154a52267a69.tar.gz sonarqube-9d2a38de3347dc85890fae454f82154a52267a69.zip |
SONAR-17588 Allow project onboarding when multiple Bitbucket integrations are configured
Diffstat (limited to 'server/sonar-web')
27 files changed, 539 insertions, 224 deletions
diff --git a/server/sonar-web/src/main/js/apps/create/project/AlmSettingsInstanceDropdown.tsx b/server/sonar-web/src/main/js/apps/create/project/AlmSettingsInstanceDropdown.tsx index 1bd3d726f48..6a6776fb355 100644 --- a/server/sonar-web/src/main/js/apps/create/project/AlmSettingsInstanceDropdown.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/AlmSettingsInstanceDropdown.tsx @@ -28,24 +28,25 @@ export interface AlmSettingsInstanceDropdownProps { onChangeConfig: (instance: AlmSettingsInstance) => void; } +const MIN_SIZE_INSTANCES = 2; + export default function AlmSettingsInstanceDropdown(props: AlmSettingsInstanceDropdownProps) { const { almInstances, selectedAlmInstance } = props; + if (!almInstances || almInstances.length < MIN_SIZE_INSTANCES) { + return null; + } return ( - <> - {almInstances && almInstances.length > 1 ? ( - <div className="display-flex-column huge-spacer-bottom"> - <label htmlFor="alm-config-selector" className="spacer-bottom"> - {translate('alm.configuration.selector.label')} - </label> - <AlmSettingsInstanceSelector - instances={almInstances} - onChange={props.onChangeConfig} - initialValue={selectedAlmInstance ? selectedAlmInstance.key : undefined} - classNames="abs-width-400" - inputId="alm-config-selector" - /> - </div> - ) : null} - </> + <div className="display-flex-column huge-spacer-bottom"> + <label htmlFor="alm-config-selector" className="spacer-bottom"> + {translate('alm.configuration.selector.label')} + </label> + <AlmSettingsInstanceSelector + instances={almInstances} + onChange={props.onChangeConfig} + initialValue={selectedAlmInstance ? selectedAlmInstance.key : undefined} + classNames="abs-width-400" + inputId="alm-config-selector" + /> + </div> ); } diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx index a091375ccad..0ee1f087eb4 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreate.tsx @@ -30,7 +30,7 @@ import BitbucketCloudProjectCreateRenderer from './BitbucketCloudProjectCreateRe interface Props { canAdmin: boolean; - settings: AlmSettingsInstance[]; + almInstances: AlmSettingsInstance[]; loadingBindings: boolean; onProjectCreate: (projectKey: string) => void; location: Location; @@ -47,7 +47,7 @@ interface State { repositories: BitbucketCloudRepository[]; searching: boolean; searchQuery: string; - settings: AlmSettingsInstance; + selectedAlmInstance: AlmSettingsInstance; showPersonalAccessTokenForm: boolean; } @@ -67,7 +67,7 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro repositories: [], searching: false, searchQuery: '', - settings: props.settings[0], + selectedAlmInstance: props.almInstances[0], showPersonalAccessTokenForm: true, }; } @@ -77,8 +77,8 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro } componentDidUpdate(prevProps: Props) { - if (prevProps.settings.length === 0 && this.props.settings.length > 0) { - this.setState({ settings: this.props.settings[0] }, () => this.fetchData()); + if (prevProps.almInstances.length === 0 && this.props.almInstances.length > 0) { + this.setState({ selectedAlmInstance: this.props.almInstances[0] }, () => this.fetchData()); } } @@ -98,14 +98,14 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro async fetchData(more = false) { const { - settings, + selectedAlmInstance, searchQuery, projectsPaging: { pageIndex, pageSize }, showPersonalAccessTokenForm, } = this.state; - if (settings && !showPersonalAccessTokenForm) { + if (selectedAlmInstance && !showPersonalAccessTokenForm) { const { isLastPage, repositories } = await searchForBitbucketCloudRepositories( - settings.key, + selectedAlmInstance.key, searchQuery, pageSize, pageIndex @@ -174,17 +174,18 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro }; handleImport = async (repositorySlug: string) => { - const { settings } = this.state; + const { selectedAlmInstance } = this.state; - if (!settings) { + if (!selectedAlmInstance) { return; } this.setState({ importingSlug: repositorySlug }); - const result = await importBitbucketCloudRepository(settings.key, repositorySlug).catch( - () => undefined - ); + const result = await importBitbucketCloudRepository( + selectedAlmInstance.key, + repositorySlug + ).catch(() => undefined); if (this.mounted) { this.setState({ importingSlug: undefined }); @@ -195,12 +196,23 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro } }; + onSelectedAlmInstanceChange = (instance: AlmSettingsInstance) => { + this.setState({ + selectedAlmInstance: instance, + showPersonalAccessTokenForm: true, + resetPat: false, + searching: false, + searchQuery: '', + projectsPaging: { pageIndex: 1, pageSize: BITBUCKET_CLOUD_PROJECTS_PAGESIZE }, + }); + }; + render() { - const { canAdmin, loadingBindings, location } = this.props; + const { canAdmin, loadingBindings, location, almInstances } = this.props; const { importingSlug, isLastPage = true, - settings, + selectedAlmInstance, loading, loadingMore, repositories, @@ -213,7 +225,8 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro <BitbucketCloudProjectCreateRenderer importingSlug={importingSlug} isLastPage={isLastPage} - settings={settings} + selectedAlmInstance={selectedAlmInstance} + almInstances={almInstances} canAdmin={canAdmin} loadingMore={loadingMore} loading={loading || loadingBindings} @@ -221,6 +234,7 @@ export default class BitbucketCloudProjectCreate extends React.PureComponent<Pro onLoadMore={this.handleLoadMore} onPersonalAccessTokenCreated={this.handlePersonalAccessTokenCreated} onSearch={this.handleSearch} + onSelectedAlmInstanceChange={this.onSelectedAlmInstanceChange} repositories={repositories} searching={searching} searchQuery={searchQuery} diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreateRender.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreateRender.tsx index 359b1e65014..514a8db6df6 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreateRender.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketCloudProjectCreateRender.tsx @@ -22,6 +22,7 @@ import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/system'; import { BitbucketCloudRepository } from '../../../types/alm-integration'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; +import AlmSettingsInstanceDropdown from './AlmSettingsInstanceDropdown'; import BitbucketCloudSearchForm from './BitbucketCloudSearchForm'; import CreateProjectPageHeader from './CreateProjectPageHeader'; import PersonalAccessTokenForm from './PersonalAccessTokenForm'; @@ -37,21 +38,24 @@ export interface BitbucketCloudProjectCreateRendererProps { onLoadMore: () => void; onPersonalAccessTokenCreated: () => void; onSearch: (searchQuery: string) => void; + onSelectedAlmInstanceChange: (instance: AlmSettingsInstance) => void; repositories?: BitbucketCloudRepository[]; resetPat: boolean; searching: boolean; searchQuery: string; showPersonalAccessTokenForm: boolean; - settings?: AlmSettingsInstance; + almInstances: AlmSettingsInstance[]; + selectedAlmInstance?: AlmSettingsInstance; } export default function BitbucketCloudProjectCreateRenderer( props: BitbucketCloudProjectCreateRendererProps ) { const { + almInstances, importingSlug, isLastPage, - settings, + selectedAlmInstance, canAdmin, loading, loadingMore, @@ -77,17 +81,24 @@ export default function BitbucketCloudProjectCreateRenderer( </span> } /> + + <AlmSettingsInstanceDropdown + almInstances={almInstances} + selectedAlmInstance={selectedAlmInstance} + onChangeConfig={props.onSelectedAlmInstanceChange} + /> + {loading && <i className="spinner" />} - {!loading && !settings && ( + {!loading && !selectedAlmInstance && ( <WrongBindingCountAlert alm={AlmKeys.BitbucketCloud} canAdmin={!!canAdmin} /> )} {!loading && - settings && + selectedAlmInstance && (showPersonalAccessTokenForm ? ( <PersonalAccessTokenForm - almSetting={settings} + almSetting={selectedAlmInstance} resetPat={resetPat} onPersonalAccessTokenCreated={props.onPersonalAccessTokenCreated} /> diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreate.tsx index 97b08aeed0d..92ad18e876b 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreate.tsx @@ -36,7 +36,7 @@ import { DEFAULT_BBS_PAGE_SIZE } from './constants'; interface Props { canAdmin: boolean; - bitbucketSettings: AlmSettingsInstance[]; + almInstances: AlmSettingsInstance[]; loadingBindings: boolean; onProjectCreate: (projectKey: string) => void; location: Location; @@ -44,7 +44,7 @@ interface Props { } interface State { - bitbucketSetting?: AlmSettingsInstance; + selectedAlmInstance?: AlmSettingsInstance; importing: boolean; loading: boolean; projects?: BitbucketProject[]; @@ -63,7 +63,7 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S this.state = { // For now, we only handle a single instance. So we always use the first // one from the list. - bitbucketSetting: props.bitbucketSettings[0], + selectedAlmInstance: props.almInstances[0], importing: false, loading: false, searching: false, @@ -76,8 +76,8 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S } componentDidUpdate(prevProps: Props) { - if (prevProps.bitbucketSettings.length === 0 && this.props.bitbucketSettings.length > 0) { - this.setState({ bitbucketSetting: this.props.bitbucketSettings[0] }, () => + if (prevProps.almInstances.length === 0 && this.props.almInstances.length > 0) { + this.setState({ selectedAlmInstance: this.props.almInstances[0] }, () => this.fetchInitialData() ); } @@ -112,27 +112,27 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S }; fetchBitbucketProjects = (): Promise<BitbucketProject[] | undefined> => { - const { bitbucketSetting } = this.state; + const { selectedAlmInstance } = this.state; - if (!bitbucketSetting) { + if (!selectedAlmInstance) { return Promise.resolve(undefined); } - return getBitbucketServerProjects(bitbucketSetting.key).then(({ projects }) => projects); + return getBitbucketServerProjects(selectedAlmInstance.key).then(({ projects }) => projects); }; fetchBitbucketRepositories = ( projects: BitbucketProject[] ): Promise<BitbucketProjectRepositories | undefined> => { - const { bitbucketSetting } = this.state; + const { selectedAlmInstance } = this.state; - if (!bitbucketSetting) { + if (!selectedAlmInstance) { return Promise.resolve(undefined); } return Promise.all( projects.map((p) => { - return getBitbucketServerRepositories(bitbucketSetting.key, p.name).then( + return getBitbucketServerRepositories(selectedAlmInstance.key, p.name).then( ({ isLastPage, repositories }) => { // Because the WS uses the project name rather than its key to find // repositories, we can match more repositories than we expect. For @@ -183,15 +183,15 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S }; handleImportRepository = () => { - const { bitbucketSetting, selectedRepository } = this.state; + const { selectedAlmInstance, selectedRepository } = this.state; - if (!bitbucketSetting || !selectedRepository) { + if (!selectedAlmInstance || !selectedRepository) { return; } this.setState({ importing: true }); importBitbucketServerProject( - bitbucketSetting.key, + selectedAlmInstance.key, selectedRepository.projectKey, selectedRepository.slug ) @@ -209,9 +209,9 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S }; handleSearch = (query: string) => { - const { bitbucketSetting } = this.state; + const { selectedAlmInstance } = this.state; - if (!bitbucketSetting) { + if (!selectedAlmInstance) { return; } @@ -221,7 +221,7 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S } this.setState({ searching: true, selectedRepository: undefined }); - searchForBitbucketServerRepositories(bitbucketSetting.key, query) + searchForBitbucketServerRepositories(selectedAlmInstance.key, query) .then(({ repositories }) => { if (this.mounted) { this.setState({ searching: false, searchResults: repositories }); @@ -238,10 +238,19 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S this.setState({ selectedRepository }); }; + onSelectedAlmInstanceChange = (instance: AlmSettingsInstance) => { + this.setState({ + selectedAlmInstance: instance, + showPersonalAccessTokenForm: true, + searching: false, + searchResults: undefined, + }); + }; + render() { - const { canAdmin, loadingBindings, location } = this.props; + const { canAdmin, loadingBindings, location, almInstances } = this.props; const { - bitbucketSetting, + selectedAlmInstance, importing, loading, projectRepositories, @@ -254,7 +263,8 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S return ( <BitbucketCreateProjectRenderer - bitbucketSetting={bitbucketSetting} + selectedAlmInstance={selectedAlmInstance} + almInstances={almInstances} canAdmin={canAdmin} importing={importing} loading={loading || loadingBindings} @@ -262,6 +272,7 @@ export default class BitbucketProjectCreate extends React.PureComponent<Props, S onPersonalAccessTokenCreated={this.handlePersonalAccessTokenCreated} onSearch={this.handleSearch} onSelectRepository={this.handleSelectRepository} + onSelectedAlmInstanceChange={this.onSelectedAlmInstanceChange} projectRepositories={projectRepositories} projects={projects} resetPat={Boolean(location.query.resetPat)} diff --git a/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx b/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx index 4c001740ea6..4a0f98f84ba 100644 --- a/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/BitbucketProjectCreateRenderer.tsx @@ -28,13 +28,15 @@ import { BitbucketRepository, } from '../../../types/alm-integration'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; +import AlmSettingsInstanceDropdown from './AlmSettingsInstanceDropdown'; import BitbucketImportRepositoryForm from './BitbucketImportRepositoryForm'; import CreateProjectPageHeader from './CreateProjectPageHeader'; import PersonalAccessTokenForm from './PersonalAccessTokenForm'; import WrongBindingCountAlert from './WrongBindingCountAlert'; export interface BitbucketProjectCreateRendererProps { - bitbucketSetting?: AlmSettingsInstance; + selectedAlmInstance?: AlmSettingsInstance; + almInstances: AlmSettingsInstance[]; canAdmin?: boolean; importing: boolean; loading: boolean; @@ -42,6 +44,7 @@ export interface BitbucketProjectCreateRendererProps { onSearch: (query: string) => void; onSelectRepository: (repo: BitbucketRepository) => void; onPersonalAccessTokenCreated: () => void; + onSelectedAlmInstanceChange: (instance: AlmSettingsInstance) => void; projects?: BitbucketProject[]; projectRepositories?: BitbucketProjectRepositories; resetPat: boolean; @@ -53,7 +56,8 @@ export interface BitbucketProjectCreateRendererProps { export default function BitbucketProjectCreateRenderer(props: BitbucketProjectCreateRendererProps) { const { - bitbucketSetting, + almInstances, + selectedAlmInstance, canAdmin, importing, loading, @@ -96,17 +100,23 @@ export default function BitbucketProjectCreateRenderer(props: BitbucketProjectCr } /> + <AlmSettingsInstanceDropdown + almInstances={almInstances} + selectedAlmInstance={selectedAlmInstance} + onChangeConfig={props.onSelectedAlmInstanceChange} + /> + {loading && <i className="spinner" />} - {!loading && !bitbucketSetting && ( + {!loading && !selectedAlmInstance && ( <WrongBindingCountAlert alm={AlmKeys.BitbucketServer} canAdmin={!!canAdmin} /> )} {!loading && - bitbucketSetting && + selectedAlmInstance && (showPersonalAccessTokenForm ? ( <PersonalAccessTokenForm - almSetting={bitbucketSetting} + almSetting={selectedAlmInstance} onPersonalAccessTokenCreated={props.onPersonalAccessTokenCreated} resetPat={resetPat} /> diff --git a/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx b/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx index 22f27994a94..ac16e767c1d 100644 --- a/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx @@ -24,11 +24,10 @@ import classNames from 'classnames'; import * as React from 'react'; import withAppStateContext from '../../../app/components/app-state/withAppStateContext'; import ChevronsIcon from '../../../components/icons/ChevronsIcon'; -import { translate, translateWithParameters } from '../../../helpers/l10n'; +import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/system'; -import { AlmKeys } from '../../../types/alm-settings'; +import { AlmKeys, AlmKeysUnion } from '../../../types/alm-settings'; import { AppState } from '../../../types/appstate'; -import { ALLOWED_MULTIPLE_CONFIGS } from './constants'; import { CreateProjectModes } from './types'; export interface CreateProjectModeSelectionProps { @@ -43,35 +42,18 @@ export interface CreateProjectModeSelectionProps { const DEFAULT_ICON_SIZE = 50; -function getErrorMessage( - hasTooManyConfig: boolean, - hasConfig: boolean, - canAdmin: boolean | undefined, - alm: AlmKeys -) { - if (hasTooManyConfig) { - return translateWithParameters( - 'onboarding.create_project.too_many_alm_instances_X', - translate('alm', alm) - ); - } else if (!hasConfig) { +function getErrorMessage(hasConfig: boolean, canAdmin: boolean | undefined) { + if (!hasConfig) { return canAdmin ? translate('onboarding.create_project.alm_not_configured.admin') : translate('onboarding.create_project.alm_not_configured'); } -} - -function getMode( - isBitbucketOption: boolean, - hasBitbucketCloudConf: boolean, - mode: CreateProjectModes -) { - return isBitbucketOption && hasBitbucketCloudConf ? CreateProjectModes.BitbucketCloud : mode; + return undefined; } function renderAlmOption( props: CreateProjectModeSelectionProps, - alm: AlmKeys.Azure | AlmKeys.BitbucketServer | AlmKeys.GitHub | AlmKeys.GitLab, + alm: AlmKeysUnion, mode: CreateProjectModes, last = false ) { @@ -80,30 +62,26 @@ function renderAlmOption( appState: { canAdmin }, loadingBindings, } = props; - - const hasBitbucketCloudConf = almCounts[AlmKeys.BitbucketCloud] > 0; - const isBitbucketOption = alm === AlmKeys.BitbucketServer; - - const count = isBitbucketOption - ? almCounts[AlmKeys.BitbucketServer] + almCounts[AlmKeys.BitbucketCloud] - : almCounts[alm]; + const count = almCounts[alm]; const hasConfig = count > 0; - const hasTooManyConfig = count > 1 && !ALLOWED_MULTIPLE_CONFIGS.includes(alm); - const disabled = loadingBindings || hasTooManyConfig || (!hasConfig && !canAdmin); + const disabled = loadingBindings || (!hasConfig && !canAdmin); const onClick = () => { - if (hasTooManyConfig || (!hasConfig && !canAdmin)) { + if (!hasConfig && !canAdmin) { return null; } if (!hasConfig && canAdmin) { - return props.onConfigMode(alm); + const configMode = alm === AlmKeys.BitbucketCloud ? AlmKeys.BitbucketServer : alm; + return props.onConfigMode(configMode); } - return props.onSelectMode(getMode(isBitbucketOption, hasBitbucketCloudConf, mode)); + return props.onSelectMode(mode); }; - const errorMessage = getErrorMessage(hasTooManyConfig, hasConfig, canAdmin, alm); + const errorMessage = getErrorMessage(hasConfig, canAdmin); + + const svgFileName = alm === AlmKeys.BitbucketCloud ? AlmKeys.BitbucketServer : alm; return ( <div className="display-flex-column"> @@ -119,7 +97,7 @@ function renderAlmOption( <img alt="" // Should be ignored by screen readers height={DEFAULT_ICON_SIZE} - src={`${getBaseUrl()}/images/alm/${alm}.svg`} + src={`${getBaseUrl()}/images/alm/${svgFileName}.svg`} /> <div className="medium big-spacer-top abs-height-50 display-flex-center"> {translate('onboarding.create_project.select_method', alm)} @@ -164,6 +142,7 @@ export function CreateProjectModeSelection(props: CreateProjectModeSelectionProp <div className="big-spacer-top huge-spacer-bottom display-flex-center"> {renderAlmOption(props, AlmKeys.Azure, CreateProjectModes.AzureDevOps)} {renderAlmOption(props, AlmKeys.BitbucketServer, CreateProjectModes.BitbucketServer)} + {renderAlmOption(props, AlmKeys.BitbucketCloud, CreateProjectModes.BitbucketCloud)} {renderAlmOption(props, AlmKeys.GitHub, CreateProjectModes.GitHub)} {renderAlmOption(props, AlmKeys.GitLab, CreateProjectModes.GitLab, true)} </div> diff --git a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx index aa6f2ff06b6..34660ee0bb8 100644 --- a/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx @@ -179,7 +179,7 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp return ( <BitbucketProjectCreate canAdmin={!!canAdmin} - bitbucketSettings={bitbucketSettings} + almInstances={bitbucketSettings} loadingBindings={loading} location={location} onProjectCreate={this.handleProjectCreate} @@ -195,7 +195,7 @@ export class CreateProjectPage extends React.PureComponent<CreateProjectPageProp location={location} onProjectCreate={this.handleProjectCreate} router={router} - settings={bitbucketCloudSettings} + almInstances={bitbucketCloudSettings} /> ); } diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreate-test.tsx index 7d2263cc0b4..4aee42212ca 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreate-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreate-test.tsx @@ -46,10 +46,10 @@ jest.mock('../../../../api/alm-integrations', () => { }); it('Should render correctly', async () => { - const wrapper = shallowRender({ settings: [] }); + const wrapper = shallowRender({ almInstances: [] }); await waitAndUpdate(wrapper); expect(wrapper).toMatchSnapshot(); - wrapper.setProps({ settings: [mockBitbucketCloudAlmSettingsInstance()] }); + wrapper.setProps({ almInstances: [mockBitbucketCloudAlmSettingsInstance()] }); await waitAndUpdate(wrapper); expect(wrapper).toMatchSnapshot('Setting changeds'); }); @@ -174,7 +174,7 @@ function shallowRender(props?: Partial<BitbucketCloudProjectCreate['props']>) { location={mockLocation()} canAdmin={true} router={mockRouter()} - settings={[mockBitbucketCloudAlmSettingsInstance()]} + almInstances={[mockBitbucketCloudAlmSettingsInstance()]} {...props} /> ); diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreateRender-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreateRender-test.tsx index 951aa97fbd1..43c4f5c6b80 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreateRender-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketCloudProjectCreateRender-test.tsx @@ -26,7 +26,7 @@ import BitbucketCloudProjectCreateRenderer, { it('Should render correctly', () => { expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ settings: undefined })).toMatchSnapshot('Wrong config'); + expect(shallowRender({ selectedAlmInstance: undefined })).toMatchSnapshot('Wrong config'); expect(shallowRender({ loading: true })).toMatchSnapshot('Loading...'); expect( shallowRender({ @@ -48,7 +48,9 @@ function shallowRender(props?: Partial<BitbucketCloudProjectCreateRendererProps> resetPat={false} searching={false} searchQuery="" - settings={mockBitbucketCloudAlmSettingsInstance()} + selectedAlmInstance={mockBitbucketCloudAlmSettingsInstance()} + almInstances={[mockBitbucketCloudAlmSettingsInstance()]} + onSelectedAlmInstanceChange={jest.fn()} showPersonalAccessTokenForm={false} {...props} /> diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx index c4d108190ca..91a6ea85605 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreate-test.tsx @@ -66,7 +66,7 @@ beforeEach(jest.clearAllMocks); it('should render correctly', async () => { expect(shallowRender()).toMatchSnapshot(); - expect(shallowRender({ bitbucketSettings: [] })).toMatchSnapshot('No setting'); + expect(shallowRender({ almInstances: [] })).toMatchSnapshot('No setting'); const wrapper = shallowRender(); (getBitbucketServerRepositories as jest.Mock).mockRejectedValueOnce({}); @@ -130,7 +130,7 @@ it('should correctly handle search', async () => { }); it('should behave correctly when no setting', async () => { - const wrapper = shallowRender({ bitbucketSettings: [] }); + const wrapper = shallowRender({ almInstances: [] }); await wrapper.instance().handleSearch(''); await wrapper.instance().handleImportRepository(); await wrapper.instance().fetchBitbucketRepositories([mockBitbucketProject()]); @@ -144,7 +144,7 @@ function shallowRender(props: Partial<BitbucketProjectCreate['props']> = {}) { return shallow<BitbucketProjectCreate>( <BitbucketProjectCreate canAdmin={false} - bitbucketSettings={[mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer, key: 'foo' })]} + almInstances={[mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer, key: 'foo' })]} loadingBindings={false} location={mockLocation()} router={mockRouter()} diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx index d771028e1df..41dc80e94e2 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/BitbucketProjectCreateRenderer-test.tsx @@ -37,10 +37,10 @@ it('should render correctly', () => { expect(shallowRender({ selectedRepository: mockBitbucketRepository() })).toMatchSnapshot( 'selected repo' ); - expect(shallowRender({ bitbucketSetting: undefined })).toMatchSnapshot( + expect(shallowRender({ selectedAlmInstance: undefined })).toMatchSnapshot( 'invalid config, regular user' ); - expect(shallowRender({ bitbucketSetting: undefined, canAdmin: true })).toMatchSnapshot( + expect(shallowRender({ selectedAlmInstance: undefined, canAdmin: true })).toMatchSnapshot( 'invalid config, admin user' ); }); @@ -48,7 +48,9 @@ it('should render correctly', () => { function shallowRender(props: Partial<BitbucketProjectCreateRendererProps> = {}) { return shallow<BitbucketProjectCreateRendererProps>( <BitbucketProjectCreateRenderer - bitbucketSetting={mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer })} + selectedAlmInstance={mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer })} + almInstances={[mockAlmSettingsInstance({ alm: AlmKeys.BitbucketServer })]} + onSelectedAlmInstanceChange={jest.fn()} importing={false} loading={false} onImportRepository={jest.fn()} diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectModeSelection-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectModeSelection-test.tsx index 0301387ae44..e677e2a580d 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectModeSelection-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectModeSelection-test.tsx @@ -79,10 +79,14 @@ it('should correctly pass the selected mode up', () => { onSelectMode.mockClear(); click(wrapper.find(almButton).at(2)); - expect(onSelectMode).toHaveBeenCalledWith(CreateProjectModes.GitHub); + expect(onSelectMode).toHaveBeenCalledWith(CreateProjectModes.BitbucketCloud); onSelectMode.mockClear(); click(wrapper.find(almButton).at(3)); + expect(onSelectMode).toHaveBeenCalledWith(CreateProjectModes.GitHub); + onSelectMode.mockClear(); + + click(wrapper.find(almButton).at(4)); expect(onSelectMode).toHaveBeenCalledWith(CreateProjectModes.GitLab); onSelectMode.mockClear(); @@ -91,7 +95,7 @@ it('should correctly pass the selected mode up', () => { { [AlmKeys.BitbucketCloud]: 1, [AlmKeys.BitbucketServer]: 0 } ); - click(wrapper.find(almButton).at(1)); + click(wrapper.find(almButton).at(2)); expect(onSelectMode).toHaveBeenCalledWith(CreateProjectModes.BitbucketCloud); onSelectMode.mockClear(); }); @@ -136,7 +140,7 @@ function shallowRender( ) { const almCounts = { [AlmKeys.Azure]: 1, - [AlmKeys.BitbucketCloud]: 0, + [AlmKeys.BitbucketCloud]: 1, [AlmKeys.BitbucketServer]: 1, [AlmKeys.GitHub]: 1, [AlmKeys.GitLab]: 1, diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreate-test.tsx.snap index 8861fde1541..efaf694bc72 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreate-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreate-test.tsx.snap @@ -2,6 +2,7 @@ exports[`Should render correctly 1`] = ` <BitbucketCloudProjectCreateRenderer + almInstances={Array []} canAdmin={true} isLastPage={true} loading={false} @@ -10,6 +11,7 @@ exports[`Should render correctly 1`] = ` onLoadMore={[Function]} onPersonalAccessTokenCreated={[Function]} onSearch={[Function]} + onSelectedAlmInstanceChange={[Function]} repositories={Array []} resetPat={false} searchQuery="" @@ -20,6 +22,14 @@ exports[`Should render correctly 1`] = ` exports[`Should render correctly: Setting changeds 1`] = ` <BitbucketCloudProjectCreateRenderer + almInstances={ + Array [ + Object { + "alm": "bitbucketcloud", + "key": "key", + }, + ] + } canAdmin={true} isLastPage={true} loading={false} @@ -28,11 +38,12 @@ exports[`Should render correctly: Setting changeds 1`] = ` onLoadMore={[Function]} onPersonalAccessTokenCreated={[Function]} onSearch={[Function]} + onSelectedAlmInstanceChange={[Function]} repositories={Array []} resetPat={false} searchQuery="" searching={false} - settings={ + selectedAlmInstance={ Object { "alm": "bitbucketcloud", "key": "key", diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreateRender-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreateRender-test.tsx.snap index eb413b12cc6..ef927ced83a 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreateRender-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketCloudProjectCreateRender-test.tsx.snap @@ -17,6 +17,23 @@ exports[`Should render correctly 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucketcloud", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucketcloud", + "key": "key", + } + } + /> <BitbucketCloudSearchForm isLastPage={true} loadingMore={false} @@ -46,6 +63,23 @@ exports[`Should render correctly: Loading... 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucketcloud", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucketcloud", + "key": "key", + } + } + /> <i className="spinner" /> @@ -69,6 +103,23 @@ exports[`Should render correctly: Need App password 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucketcloud", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucketcloud", + "key": "key", + } + } + /> <PersonalAccessTokenForm almSetting={ Object { @@ -99,6 +150,17 @@ exports[`Should render correctly: Wrong config 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucketcloud", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + /> <WrongBindingCountAlert alm="bitbucketcloud" canAdmin={false} diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreate-test.tsx.snap index c06e0b818bf..e168e70e45b 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreate-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreate-test.tsx.snap @@ -2,11 +2,13 @@ exports[`should render correctly 1`] = ` <BitbucketProjectCreateRenderer - bitbucketSetting={ - Object { - "alm": "bitbucket", - "key": "foo", - } + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "foo", + }, + ] } canAdmin={false} importing={false} @@ -15,19 +17,28 @@ exports[`should render correctly 1`] = ` onPersonalAccessTokenCreated={[Function]} onSearch={[Function]} onSelectRepository={[Function]} + onSelectedAlmInstanceChange={[Function]} resetPat={false} searching={false} + selectedAlmInstance={ + Object { + "alm": "bitbucket", + "key": "foo", + } + } showPersonalAccessTokenForm={true} /> `; exports[`should render correctly: No repository 1`] = ` <BitbucketProjectCreateRenderer - bitbucketSetting={ - Object { - "alm": "bitbucket", - "key": "foo", - } + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "foo", + }, + ] } canAdmin={false} importing={false} @@ -36,6 +47,7 @@ exports[`should render correctly: No repository 1`] = ` onPersonalAccessTokenCreated={[Function]} onSearch={[Function]} onSelectRepository={[Function]} + onSelectedAlmInstanceChange={[Function]} projects={ Array [ Object { @@ -52,12 +64,19 @@ exports[`should render correctly: No repository 1`] = ` } resetPat={false} searching={false} + selectedAlmInstance={ + Object { + "alm": "bitbucket", + "key": "foo", + } + } showPersonalAccessTokenForm={false} /> `; exports[`should render correctly: No setting 1`] = ` <BitbucketProjectCreateRenderer + almInstances={Array []} canAdmin={false} importing={false} loading={false} @@ -65,6 +84,7 @@ exports[`should render correctly: No setting 1`] = ` onPersonalAccessTokenCreated={[Function]} onSearch={[Function]} onSelectRepository={[Function]} + onSelectedAlmInstanceChange={[Function]} resetPat={false} searching={false} showPersonalAccessTokenForm={true} diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreateRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreateRenderer-test.tsx.snap index c499c0accea..b9f83f3dd5c 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreateRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/BitbucketProjectCreateRenderer-test.tsx.snap @@ -34,6 +34,23 @@ exports[`should render correctly: default 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucket", + "key": "key", + } + } + /> <BitbucketImportRepositoryForm disableRepositories={false} onSearch={[MockFunction]} @@ -101,6 +118,23 @@ exports[`should render correctly: importing 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucket", + "key": "key", + } + } + /> <BitbucketImportRepositoryForm disableRepositories={true} onSearch={[MockFunction]} @@ -168,6 +202,17 @@ exports[`should render correctly: invalid config, admin user 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + /> <WrongBindingCountAlert alm="bitbucket" canAdmin={true} @@ -209,6 +254,17 @@ exports[`should render correctly: invalid config, regular user 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + /> <WrongBindingCountAlert alm="bitbucket" canAdmin={false} @@ -250,6 +306,23 @@ exports[`should render correctly: loading 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucket", + "key": "key", + } + } + /> <i className="spinner" /> @@ -274,6 +347,23 @@ exports[`should render correctly: pat form 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucket", + "key": "key", + } + } + /> <PersonalAccessTokenForm almSetting={ Object { @@ -321,6 +411,23 @@ exports[`should render correctly: selected repo 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "bitbucket", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "bitbucket", + "key": "key", + } + } + /> <BitbucketImportRepositoryForm disableRepositories={false} onSearch={[MockFunction]} diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectModeSelection-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectModeSelection-test.tsx.snap index 2d6c27f9ac7..36a8a852f6b 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectModeSelection-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectModeSelection-test.tsx.snap @@ -67,6 +67,27 @@ exports[`should render correctly: default 1`] = ` <img alt="" height={50} + src="/images/alm/bitbucket.svg" + /> + <div + className="medium big-spacer-top abs-height-50 display-flex-center" + > + onboarding.create_project.select_method.bitbucketcloud + </div> + </button> + </div> + <div + className="display-flex-column" + > + <button + className="button button-huge display-flex-column create-project-mode-type-alm big-spacer-right" + disabled={false} + onClick={[Function]} + type="button" + > + <img + alt="" + height={50} src="/images/alm/github.svg" /> <div @@ -197,6 +218,27 @@ exports[`should render correctly: invalid configs, admin 1`] = ` <img alt="" height={50} + src="/images/alm/bitbucket.svg" + /> + <div + className="medium big-spacer-top abs-height-50 display-flex-center" + > + onboarding.create_project.select_method.bitbucketcloud + </div> + </button> + </div> + <div + className="display-flex-column" + > + <button + className="button button-huge display-flex-column create-project-mode-type-alm big-spacer-right" + disabled={false} + onClick={[Function]} + type="button" + > + <img + alt="" + height={50} src="/images/alm/github.svg" /> <div @@ -327,6 +369,37 @@ exports[`should render correctly: invalid configs, admin 2`] = ` <img alt="" height={50} + src="/images/alm/bitbucket.svg" + /> + <div + className="medium big-spacer-top abs-height-50 display-flex-center" + > + onboarding.create_project.select_method.bitbucketcloud + </div> + <p + className="text-muted small spacer-top" + style={ + Object { + "lineHeight": 1.5, + } + } + > + onboarding.create_project.alm_not_configured.admin + </p> + </button> + </div> + <div + className="display-flex-column" + > + <button + className="button button-huge display-flex-column create-project-mode-type-alm big-spacer-right" + disabled={false} + onClick={[Function]} + type="button" + > + <img + alt="" + height={50} src="/images/alm/github.svg" /> <div @@ -457,6 +530,27 @@ exports[`should render correctly: invalid configs, not admin 1`] = ` <img alt="" height={50} + src="/images/alm/bitbucket.svg" + /> + <div + className="medium big-spacer-top abs-height-50 display-flex-center" + > + onboarding.create_project.select_method.bitbucketcloud + </div> + </button> + </div> + <div + className="display-flex-column" + > + <button + className="button button-huge display-flex-column create-project-mode-type-alm big-spacer-right" + disabled={false} + onClick={[Function]} + type="button" + > + <img + alt="" + height={50} src="/images/alm/github.svg" /> <div @@ -589,6 +683,33 @@ exports[`should render correctly: loading instances 1`] = ` <img alt="" height={50} + src="/images/alm/bitbucket.svg" + /> + <div + className="medium big-spacer-top abs-height-50 display-flex-center" + > + onboarding.create_project.select_method.bitbucketcloud + </div> + <span> + onboarding.create_project.check_alm_supported + <i + className="little-spacer-left spinner" + /> + </span> + </button> + </div> + <div + className="display-flex-column" + > + <button + className="button button-huge display-flex-column create-project-mode-type-alm disabled big-spacer-right" + disabled={true} + onClick={[Function]} + type="button" + > + <img + alt="" + height={50} src="/images/alm/github.svg" /> <div @@ -746,6 +867,37 @@ exports[`should render correctly: no alm conf yet, admin 1`] = ` <img alt="" height={50} + src="/images/alm/bitbucket.svg" + /> + <div + className="medium big-spacer-top abs-height-50 display-flex-center" + > + onboarding.create_project.select_method.bitbucketcloud + </div> + <p + className="text-muted small spacer-top" + style={ + Object { + "lineHeight": 1.5, + } + } + > + onboarding.create_project.alm_not_configured.admin + </p> + </button> + </div> + <div + className="display-flex-column" + > + <button + className="button button-huge display-flex-column create-project-mode-type-alm big-spacer-right" + disabled={false} + onClick={[Function]} + type="button" + > + <img + alt="" + height={50} src="/images/alm/github.svg" /> <div diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap index 623e4d2b0dc..6ec13628e53 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap @@ -143,7 +143,7 @@ exports[`should render correctly for bitbucket mode 1`] = ` id="create-project" > <BitbucketProjectCreate - bitbucketSettings={Array []} + almInstances={Array []} canAdmin={false} loadingBindings={true} location={ @@ -194,6 +194,7 @@ exports[`should render correctly for bitbucketcloud mode 1`] = ` id="create-project" > <BitbucketCloudProjectCreate + almInstances={Array []} canAdmin={false} loadingBindings={true} location={ @@ -222,7 +223,6 @@ exports[`should render correctly for bitbucketcloud mode 1`] = ` "setRouteLeaveHook": [MockFunction], } } - settings={Array []} /> </div> </Fragment> diff --git a/server/sonar-web/src/main/js/apps/create/project/constants.ts b/server/sonar-web/src/main/js/apps/create/project/constants.ts index 68567ef7eea..d47426c1831 100644 --- a/server/sonar-web/src/main/js/apps/create/project/constants.ts +++ b/server/sonar-web/src/main/js/apps/create/project/constants.ts @@ -1,5 +1,3 @@ -import { AlmKeys } from '../../../types/alm-settings'; - /* * SonarQube * Copyright (C) 2009-2022 SonarSource SA @@ -22,5 +20,3 @@ import { AlmKeys } from '../../../types/alm-settings'; export const PROJECT_NAME_MAX_LEN = 255; export const DEFAULT_BBS_PAGE_SIZE = 25; - -export const ALLOWED_MULTIPLE_CONFIGS = [AlmKeys.GitLab, AlmKeys.Azure, AlmKeys.GitHub]; diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx index 97abfd16f81..b764b4dbd14 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectCreationMenu.tsx @@ -31,7 +31,6 @@ import { hasGlobalPermission } from '../../../helpers/users'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; import { Permissions } from '../../../types/permissions'; import { LoggedInUser } from '../../../types/users'; -import { ALLOWED_MULTIPLE_CONFIGS } from '../../create/project/constants'; import ProjectCreationMenuItem from './ProjectCreationMenuItem'; interface Props { @@ -80,18 +79,10 @@ export class ProjectCreationMenu extends React.PureComponent<Props, State> { const almSettings: AlmSettingsInstance[] = await getAlmSettings().catch(() => []); - // Import is only available if exactly one binding is configured const boundAlms = IMPORT_COMPATIBLE_ALMS.filter((key) => { - let currentAlmSettings: AlmSettingsInstance[]; - if (key === AlmKeys.BitbucketServer || key === AlmKeys.BitbucketCloud) { - currentAlmSettings = almSettings.filter( - (s) => s.alm === AlmKeys.BitbucketCloud || s.alm === AlmKeys.BitbucketServer - ); - } else { - currentAlmSettings = almSettings.filter((s) => s.alm === key); - } + const currentAlmSettings = almSettings.filter((s) => s.alm === key); return ( - this.configLengthChecker(key, currentAlmSettings.length) && + currentAlmSettings.length > 0 && key === currentAlmSettings[0].alm && this.almSettingIsValid(currentAlmSettings[0]) ); @@ -104,10 +95,6 @@ export class ProjectCreationMenu extends React.PureComponent<Props, State> { } }; - configLengthChecker = (key: AlmKeys, length: number) => { - return ALLOWED_MULTIPLE_CONFIGS.includes(key) ? length > 0 : length === 1; - }; - render() { const { className, currentUser } = this.props; const { boundAlms } = this.state; diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx index a73c1ea5999..87b621ecebe 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx @@ -117,11 +117,22 @@ it('should filter alm bindings appropriately', async () => { wrapper = shallowRender(); await waitAndUpdate(wrapper); - expect(wrapper.state().boundAlms).toEqual([AlmKeys.Azure, AlmKeys.GitHub, AlmKeys.GitLab]); + expect(wrapper.state().boundAlms).toEqual([ + AlmKeys.Azure, + AlmKeys.BitbucketServer, + AlmKeys.BitbucketCloud, + AlmKeys.GitHub, + AlmKeys.GitLab, + ]); wrapper = shallowRender(); await waitAndUpdate(wrapper); - expect(wrapper.state().boundAlms).toEqual([AlmKeys.Azure, AlmKeys.GitHub, AlmKeys.GitLab]); + expect(wrapper.state().boundAlms).toEqual([ + AlmKeys.Azure, + AlmKeys.BitbucketServer, + AlmKeys.GitHub, + AlmKeys.GitLab, + ]); }); function shallowRender(overrides: Partial<ProjectCreationMenu['props']> = {}) { diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx index ee27acc7694..2d75e7a76d8 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx @@ -38,13 +38,11 @@ import { AlmSettingsBindingStatusType, } from '../../../../types/alm-settings'; import { EditionKey } from '../../../../types/editions'; -import { ALLOWED_MULTIPLE_CONFIGS } from '../../../create/project/constants'; export interface AlmBindingDefinitionBoxProps { alm: AlmKeys; branchesEnabled: boolean; definition: AlmBindingDefinitionBase; - multipleDefinitions: boolean; onCheck: (definitionKey: string) => void; onDelete: (definitionKey: string) => void; onEdit: (definitionKey: string) => void; @@ -108,23 +106,8 @@ function getPRDecorationFeatureStatus( function getImportFeatureStatus( alm: AlmKeys, definition: AlmBindingDefinitionBase, - multipleDefinitions: boolean, type: AlmSettingsBindingStatusType.Success | AlmSettingsBindingStatusType.Failure ) { - if (multipleDefinitions && !ALLOWED_MULTIPLE_CONFIGS.includes(alm)) { - return ( - <div className="display-inline-flex-center"> - <strong className="spacer-left"> - {translate('settings.almintegration.feature.alm_repo_import.disabled')} - </strong> - <HelpTooltip - className="little-spacer-left" - overlay={translate('settings.almintegration.feature.alm_repo_import.disabled.multiple')} - /> - </div> - ); - } - if (!definition.url && alm !== AlmKeys.BitbucketCloud) { return ( <div className="display-inline-flex-center"> @@ -156,7 +139,7 @@ function getPrDecoFeatureDescription(alm: AlmKeys) { } export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxProps) { - const { alm, branchesEnabled, definition, multipleDefinitions, status = DEFAULT_STATUS } = props; + const { alm, branchesEnabled, definition, status = DEFAULT_STATUS } = props; return ( <div className="boxed-group-inner bordered spacer-top spacer-bottom it__alm-binding-definition"> @@ -202,7 +185,7 @@ export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxPr {translate('settings.almintegration.feature.alm_repo_import.title')} </span> </Tooltip> - {getImportFeatureStatus(alm, definition, multipleDefinitions, status.type)} + {getImportFeatureStatus(alm, definition, status.type)} </div> )} </div> diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx index 6e1382cc881..f36e4f931c7 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmTabRenderer.tsx @@ -107,7 +107,6 @@ export default function AlmTabRenderer(props: AlmTabRendererProps) { branchesEnabled={branchesEnabled} definition={def} key={def.key} - multipleDefinitions={definitions.length > 1} onCheck={props.onCheck} onDelete={props.onDelete} onEdit={props.onEdit} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx index 8a1f5e2754c..e32365f2f57 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/AlmBindingDefinitionBox-test.tsx @@ -31,7 +31,6 @@ import AlmBindingDefinitionBox, { AlmBindingDefinitionBoxProps } from '../AlmBin it('should render correctly', () => { expect(shallowRender()).toMatchSnapshot('default'); - expect(shallowRender({ multipleDefinitions: true })).toMatchSnapshot('multiple definitions'); expect( shallowRender({ status: mockAlmSettingsBindingStatus({ @@ -106,7 +105,6 @@ function shallowRender(props: Partial<AlmBindingDefinitionBoxProps> = {}) { alm={AlmKeys.GitHub} branchesEnabled={true} definition={mockGithubBindingDefinition()} - multipleDefinitions={false} onCheck={jest.fn()} onDelete={jest.fn()} onEdit={jest.fn()} diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap index 4afcf1ec133..afbd6543c06 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmBindingDefinitionBox-test.tsx.snap @@ -164,48 +164,6 @@ exports[`should render correctly: error 1`] = ` </div> `; -exports[`should render correctly: multiple definitions 1`] = ` -<div - className="boxed-group-inner bordered spacer-top spacer-bottom it__alm-binding-definition" -> - <div - className="actions pull-right" - > - <Button - onClick={[Function]} - > - <EditIcon - className="spacer-right" - /> - edit - </Button> - <Button - className="button-red spacer-left" - onClick={[Function]} - > - <DeleteIcon - className="spacer-right" - /> - delete - </Button> - </div> - <div - className="big-spacer-bottom" - > - <h3> - key - </h3> - <span> - http://github.enterprise.com - </span> - </div> - <i - className="spinner spacer-right" - /> - settings.almintegration.checking_configuration -</div> -`; - exports[`should render correctly: success 1`] = ` <div className="boxed-group-inner bordered spacer-top spacer-bottom it__alm-binding-definition" diff --git a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap index 20c590100f6..9adea1fe647 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/settings/components/almIntegration/__tests__/__snapshots__/AlmTabRenderer-test.tsx.snap @@ -39,7 +39,6 @@ exports[`should render correctly for multi-ALM binding: editing a definition 1`] } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -88,7 +87,6 @@ exports[`should render correctly for multi-ALM binding: loaded 1`] = ` } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -137,7 +135,6 @@ exports[`should render correctly for multi-ALM binding: loading ALM definitions } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -186,7 +183,6 @@ exports[`should render correctly for multi-ALM binding: loading project count 1` } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -235,7 +231,6 @@ exports[`should render correctly for single-ALM binding 1`] = ` } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -284,7 +279,6 @@ exports[`should render correctly for single-ALM binding 2`] = ` } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -333,7 +327,6 @@ exports[`should render correctly for single-ALM binding 3`] = ` } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -426,7 +419,6 @@ exports[`should render correctly with validation: create a second 1`] = ` } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -480,7 +472,6 @@ exports[`should render correctly with validation: default 1`] = ` } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} @@ -570,7 +561,6 @@ exports[`should render correctly with validation: pass the correct key for bitbu } } key="key" - multipleDefinitions={false} onCheck={[MockFunction]} onDelete={[MockFunction]} onEdit={[MockFunction]} diff --git a/server/sonar-web/src/main/js/types/alm-settings.ts b/server/sonar-web/src/main/js/types/alm-settings.ts index f6609284236..8487e41e2f9 100644 --- a/server/sonar-web/src/main/js/types/alm-settings.ts +++ b/server/sonar-web/src/main/js/types/alm-settings.ts @@ -25,6 +25,13 @@ export const enum AlmKeys { GitLab = 'gitlab', } +export type AlmKeysUnion = + | AlmKeys.Azure + | AlmKeys.BitbucketServer + | AlmKeys.BitbucketCloud + | AlmKeys.GitHub + | AlmKeys.GitLab; + export type AlmBindingDefinition = | AzureBindingDefinition | GithubBindingDefinition |