diff options
author | Kevin Silva <kevin.silva@sonarsource.com> | 2022-11-17 12:01:13 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2022-11-18 20:02:49 +0000 |
commit | a292eb339f4ec2b413b855dfa1cf1cf8ac1a1667 (patch) | |
tree | e468bb8debb2d685b966b4497cb54cc861bdd41f | |
parent | 35e585d67ebb9e1af8e8caeb3f3a6552577e5ea4 (diff) | |
download | sonarqube-a292eb339f4ec2b413b855dfa1cf1cf8ac1a1667.tar.gz sonarqube-a292eb339f4ec2b413b855dfa1cf1cf8ac1a1667.zip |
SONAR-17589 Allow project onboarding when multiple Azure integrations are configured
15 files changed, 312 insertions, 220 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 new file mode 100644 index 00000000000..1bd3d726f48 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/create/project/AlmSettingsInstanceDropdown.tsx @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import AlmSettingsInstanceSelector from '../../../components/devops-platform/AlmSettingsInstanceSelector'; +import { translate } from '../../../helpers/l10n'; +import { AlmSettingsInstance } from '../../../types/alm-settings'; + +export interface AlmSettingsInstanceDropdownProps { + almInstances?: AlmSettingsInstance[]; + selectedAlmInstance?: AlmSettingsInstance; + onChangeConfig: (instance: AlmSettingsInstance) => void; +} + +export default function AlmSettingsInstanceDropdown(props: AlmSettingsInstanceDropdownProps) { + const { almInstances, selectedAlmInstance } = props; + 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} + </> + ); +} diff --git a/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx index fb2ffd7920d..1c9864fd9e4 100644 --- a/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx @@ -36,7 +36,7 @@ interface Props { canAdmin: boolean; loadingBindings: boolean; onProjectCreate: (projectKey: string) => void; - settings: AlmSettingsInstance[]; + almInstances: AlmSettingsInstance[]; location: Location; router: Router; } @@ -52,7 +52,7 @@ interface State { searchResults?: AzureRepository[]; searchQuery?: string; selectedRepository?: AzureRepository; - settings?: AlmSettingsInstance; + selectedAlmInstance?: AlmSettingsInstance; submittingToken?: boolean; tokenValidationFailed: boolean; } @@ -65,7 +65,7 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State this.state = { // For now, we only handle a single instance. So we always use the first // one from the list. - settings: props.settings[0], + selectedAlmInstance: props.almInstances[0], importing: false, loading: false, loadingRepositories: {}, @@ -76,15 +76,12 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State componentDidMount() { this.mounted = true; - this.fetchInitialData(); + this.fetchData(); } componentDidUpdate(prevProps: Props) { - if (prevProps.settings.length === 0 && this.props.settings.length > 0) { - this.setState( - { settings: this.props.settings.length === 1 ? this.props.settings[0] : undefined }, - () => this.fetchInitialData() - ); + if (prevProps.almInstances.length === 0 && this.props.almInstances.length > 0) { + this.setState({ selectedAlmInstance: this.props.almInstances[0] }, () => this.fetchData()); } } @@ -92,7 +89,7 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State this.mounted = false; } - fetchInitialData = async () => { + fetchData = async () => { this.setState({ loading: true }); const patIsValid = await this.checkPersonalAccessToken().catch(() => false); @@ -135,23 +132,23 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State }; fetchAzureProjects = (): Promise<AzureProject[] | undefined> => { - const { settings } = this.state; + const { selectedAlmInstance } = this.state; - if (!settings) { + if (!selectedAlmInstance) { return Promise.resolve(undefined); } - return getAzureProjects(settings.key).then(({ projects }) => projects); + return getAzureProjects(selectedAlmInstance.key).then(({ projects }) => projects); }; fetchAzureRepositories = (projectName: string): Promise<AzureRepository[]> => { - const { settings } = this.state; + const { selectedAlmInstance } = this.state; - if (!settings) { + if (!selectedAlmInstance) { return Promise.resolve([]); } - return getAzureRepositories(settings.key, projectName) + return getAzureRepositories(selectedAlmInstance.key, projectName) .then(({ repositories }) => repositories) .catch(() => []); }; @@ -180,9 +177,9 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State }; handleSearchRepositories = async (searchQuery: string) => { - const { settings } = this.state; + const { selectedAlmInstance } = this.state; - if (!settings) { + if (!selectedAlmInstance) { return; } @@ -194,7 +191,7 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State this.setState({ searching: true }); const searchResults: AzureRepository[] = await searchAzureRepositories( - settings.key, + selectedAlmInstance.key, searchQuery ) .then(({ repositories }) => repositories) @@ -210,16 +207,16 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State }; handleImportRepository = async () => { - const { selectedRepository, settings } = this.state; + const { selectedRepository, selectedAlmInstance } = this.state; - if (!settings || !selectedRepository) { + if (!selectedAlmInstance || !selectedRepository) { return; } this.setState({ importing: true }); const createdProject = await importAzureRepository( - settings.key, + selectedAlmInstance.key, selectedRepository.projectName, selectedRepository.name ) @@ -239,26 +236,26 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State }; checkPersonalAccessToken = () => { - const { settings } = this.state; + const { selectedAlmInstance } = this.state; - if (!settings) { + if (!selectedAlmInstance) { return Promise.resolve(false); } - return checkPersonalAccessTokenIsValid(settings.key).then(({ status }) => status); + return checkPersonalAccessTokenIsValid(selectedAlmInstance.key).then(({ status }) => status); }; handlePersonalAccessTokenCreate = async (token: string) => { - const { settings } = this.state; + const { selectedAlmInstance } = this.state; - if (!settings || token.length < 1) { + if (!selectedAlmInstance || token.length < 1) { return; } this.setState({ submittingToken: true, tokenValidationFailed: false }); try { - await setAlmPersonalAccessToken(settings.key, token); + await setAlmPersonalAccessToken(selectedAlmInstance.key, token); const patIsValid = await this.checkPersonalAccessToken(); if (this.mounted) { @@ -266,7 +263,7 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State if (patIsValid) { this.cleanUrl(); - this.fetchInitialData(); + this.fetchData(); } } } catch (e) { @@ -276,8 +273,12 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State } }; + onChangeConfig = (instance: AlmSettingsInstance) => { + this.setState({ selectedAlmInstance: instance }, () => this.fetchData()); + }; + render() { - const { canAdmin, loadingBindings, location } = this.props; + const { canAdmin, loadingBindings, location, almInstances } = this.props; const { importing, loading, @@ -289,7 +290,7 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State searchResults, searchQuery, selectedRepository, - settings, + selectedAlmInstance, submittingToken, tokenValidationFailed, } = this.state; @@ -311,10 +312,12 @@ export default class AzureProjectCreate extends React.PureComponent<Props, State searchResults={searchResults} searchQuery={searchQuery} selectedRepository={selectedRepository} - settings={settings} + almInstances={almInstances} + selectedAlmInstance={selectedAlmInstance} showPersonalAccessTokenForm={!patIsValid || Boolean(location.query.resetPat)} submittingToken={submittingToken} tokenValidationFailed={tokenValidationFailed} + onChangeConfig={this.onChangeConfig} /> ); } diff --git a/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreateRenderer.tsx b/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreateRenderer.tsx index fc5b4823c9d..22fa07d7101 100644 --- a/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreateRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/AzureProjectCreateRenderer.tsx @@ -31,6 +31,7 @@ import { AzureProject, AzureRepository } from '../../../types/alm-integration'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; import { Dict } from '../../../types/types'; import { ALM_INTEGRATION_CATEGORY } from '../../settings/constants'; +import AlmSettingsInstanceDropdown from './AlmSettingsInstanceDropdown'; import AzurePersonalAccessTokenForm from './AzurePersonalAccessTokenForm'; import AzureProjectsList from './AzureProjectsList'; import CreateProjectPageHeader from './CreateProjectPageHeader'; @@ -52,10 +53,12 @@ export interface AzureProjectCreateRendererProps { searchResults?: AzureRepository[]; searchQuery?: string; selectedRepository?: AzureRepository; - settings?: AlmSettingsInstance; + almInstances?: AlmSettingsInstance[]; + selectedAlmInstance?: AlmSettingsInstance; showPersonalAccessTokenForm?: boolean; submittingToken?: boolean; tokenValidationFailed: boolean; + onChangeConfig: (instance: AlmSettingsInstance) => void; } export default function AzureProjectCreateRenderer(props: AzureProjectCreateRendererProps) { @@ -70,15 +73,16 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend searchResults, searchQuery, selectedRepository, - settings, + almInstances, showPersonalAccessTokenForm, submittingToken, tokenValidationFailed, + selectedAlmInstance, } = props; - const settingIsValid = settings && settings.url; - const showCountError = !loading && !settings; - const showUrlError = !loading && settings && !settings.url; + const showCountError = !loading && (!almInstances || almInstances?.length === 0); + const settingIsValid = selectedAlmInstance && selectedAlmInstance.url; + const showUrlError = !loading && selectedAlmInstance && !selectedAlmInstance.url; return ( <> @@ -111,6 +115,12 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend } /> + <AlmSettingsInstanceDropdown + almInstances={almInstances} + selectedAlmInstance={selectedAlmInstance} + onChangeConfig={props.onChangeConfig} + /> + {loading && <i className="spinner" />} {showUrlError && ( @@ -137,12 +147,12 @@ export default function AzureProjectCreateRenderer(props: AzureProjectCreateRend {showCountError && <WrongBindingCountAlert alm={AlmKeys.Azure} canAdmin={!!canAdmin} />} {!loading && - settings && - settings.url && + selectedAlmInstance && + selectedAlmInstance.url && (showPersonalAccessTokenForm ? ( - <div className="display-flex-justify-center"> + <div> <AzurePersonalAccessTokenForm - almSetting={settings} + almSetting={selectedAlmInstance} onPersonalAccessTokenCreate={props.onPersonalAccessTokenCreate} submitting={submittingToken} validationFailed={tokenValidationFailed} 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 926f2fe4f89..21100831bd3 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 @@ -171,7 +171,7 @@ export class CreateProjectPage extends React.PureComponent<Props, State> { location={location} onProjectCreate={this.handleProjectCreate} router={router} - settings={azureSettings} + almInstances={azureSettings} /> ); } diff --git a/server/sonar-web/src/main/js/apps/create/project/GitlabProjectCreateRenderer.tsx b/server/sonar-web/src/main/js/apps/create/project/GitlabProjectCreateRenderer.tsx index 668420dffe2..a90b987b31a 100644 --- a/server/sonar-web/src/main/js/apps/create/project/GitlabProjectCreateRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/GitlabProjectCreateRenderer.tsx @@ -18,12 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import AlmSettingsInstanceSelector from '../../../components/devops-platform/AlmSettingsInstanceSelector'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/system'; import { GitlabProject } from '../../../types/alm-integration'; import { AlmKeys, AlmSettingsInstance } from '../../../types/alm-settings'; import { Paging } from '../../../types/types'; +import AlmSettingsInstanceDropdown from './AlmSettingsInstanceDropdown'; import CreateProjectPageHeader from './CreateProjectPageHeader'; import GitlabProjectSelectionForm from './GitlabProjectSelectionForm'; import PersonalAccessTokenForm from './PersonalAccessTokenForm'; @@ -81,20 +81,11 @@ export default function GitlabProjectCreateRenderer(props: GitlabProjectCreateRe } /> - {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> - )} + <AlmSettingsInstanceDropdown + almInstances={almInstances} + selectedAlmInstance={selectedAlmInstance} + onChangeConfig={props.onChangeConfig} + /> {loading && <i className="spinner" />} diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx index f2a80b0cf13..c033380802a 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx @@ -195,8 +195,8 @@ it('should select and import a repository', async () => { expect(wrapper.state().importing).toBe(false); }); -it('should handle no settings', () => { - const wrapper = shallowRender({ settings: [] }); +it('should handle no almInstances', () => { + const wrapper = shallowRender({ almInstances: [] }); wrapper.instance().fetchAzureProjects(); wrapper.instance().fetchAzureRepositories('whatever'); @@ -221,7 +221,7 @@ function shallowRender(overrides: Partial<AzureProjectCreate['props']> = {}) { location={mockLocation()} onProjectCreate={jest.fn()} router={mockRouter()} - settings={[mockAlmSettingsInstance({ alm: AlmKeys.Azure, key: 'foo' })]} + almInstances={[mockAlmSettingsInstance({ alm: AlmKeys.Azure, key: 'foo' })]} {...overrides} /> ); diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreateRenderer-test.tsx b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreateRenderer-test.tsx index 265a1890e03..c4549235f11 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreateRenderer-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreateRenderer-test.tsx @@ -28,19 +28,35 @@ import AzureProjectCreateRenderer, { it('should render correctly', () => { expect(shallowRender({ loading: true })).toMatchSnapshot('loading'); - expect(shallowRender({ settings: undefined })).toMatchSnapshot('no settings'); + expect(shallowRender({ almInstances: undefined })).toMatchSnapshot('no settings'); expect(shallowRender({ showPersonalAccessTokenForm: true })).toMatchSnapshot('token form'); - expect(shallowRender()).toMatchSnapshot('project list'); expect( shallowRender({ - settings: mockAlmSettingsInstance({ alm: AlmKeys.Azure }), + almInstances: [ + mockAlmSettingsInstance({ alm: AlmKeys.Azure, url: 'https://azure.company.com' }), + mockAlmSettingsInstance({ + alm: AlmKeys.Azure, + url: 'https://azure.company.com', + key: 'key2', + }), + ], + selectedAlmInstance: mockAlmSettingsInstance({ + alm: AlmKeys.Azure, + url: 'https://azure.company.com', + }), + }) + ).toMatchSnapshot('project list'); + + expect( + shallowRender({ + almInstances: [mockAlmSettingsInstance({ alm: AlmKeys.Azure })], showPersonalAccessTokenForm: true, }) ).toMatchSnapshot('setting missing url, admin'); expect( shallowRender({ canAdmin: false, - settings: mockAlmSettingsInstance({ alm: AlmKeys.Azure }), + almInstances: [mockAlmSettingsInstance({ alm: AlmKeys.Azure })], }) ).toMatchSnapshot('setting missing url, not admin'); }); @@ -62,9 +78,12 @@ function shallowRender(overrides: Partial<AzureProjectCreateRendererProps> = {}) projects={[project]} repositories={{ [project.name]: [mockAzureRepository()] }} tokenValidationFailed={false} - settings={mockAlmSettingsInstance({ alm: AlmKeys.Azure, url: 'https://azure.company.com' })} + almInstances={[ + mockAlmSettingsInstance({ alm: AlmKeys.Azure, url: 'https://azure.company.com' }), + ]} showPersonalAccessTokenForm={false} submittingToken={false} + onChangeConfig={jest.fn()} {...overrides} /> ); 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 47ddaad401e..0301387ae44 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 @@ -102,7 +102,7 @@ it('should call the proper click handler', () => { const onSelectMode = jest.fn(); const onConfigMode = jest.fn(); - let wrapper = shallowRender({ onSelectMode, onConfigMode }, { [AlmKeys.Azure]: 2 }); + let wrapper = shallowRender({ onSelectMode, onConfigMode }, { [AlmKeys.Azure]: 0 }); click(wrapper.find(almButton).at(0)); expect(onConfigMode).not.toHaveBeenCalled(); diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreate-test.tsx.snap index a3c1a9a74d7..4af7d5f4433 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreate-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreate-test.tsx.snap @@ -2,17 +2,26 @@ exports[`should render correctly 1`] = ` <AzureProjectCreateRenderer + almInstances={ + Array [ + Object { + "alm": "azure", + "key": "foo", + }, + ] + } canAdmin={true} importing={false} loading={true} loadingRepositories={Object {}} + onChangeConfig={[Function]} onImportRepository={[Function]} onOpenProject={[Function]} onPersonalAccessTokenCreate={[Function]} onSearch={[Function]} onSelectRepository={[Function]} repositories={Object {}} - settings={ + selectedAlmInstance={ Object { "alm": "azure", "key": "foo", diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap index 7b95f10bdf8..2c6ac9285f6 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap @@ -3,23 +3,6 @@ exports[`should render correctly: loading 1`] = ` <Fragment> <CreateProjectPageHeader - additionalActions={ - <div - className="display-flex-center pull-right" - > - <DeferredSpinner - className="spacer-right" - loading={false} - /> - <Button - className="button-large button-primary" - disabled={true} - onClick={[MockFunction]} - > - onboarding.create_project.import_selected_repo - </Button> - </div> - } title={ <span className="text-middle" @@ -34,6 +17,18 @@ exports[`should render correctly: loading 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "azure", + "key": "key", + "url": "https://azure.company.com", + }, + ] + } + onChangeConfig={[MockFunction]} + /> <i className="spinner" /> @@ -57,6 +52,9 @@ exports[`should render correctly: no settings 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + onChangeConfig={[MockFunction]} + /> <WrongBindingCountAlert alm="azure" canAdmin={true} @@ -98,6 +96,30 @@ exports[`should render correctly: project list 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "azure", + "key": "key", + "url": "https://azure.company.com", + }, + Object { + "alm": "azure", + "key": "key2", + "url": "https://azure.company.com", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "azure", + "key": "key", + "url": "https://azure.company.com", + } + } + /> <div className="huge-spacer-bottom" > @@ -155,29 +177,17 @@ exports[`should render correctly: setting missing url, admin 1`] = ` </span> } /> - <Alert - variant="error" - > - <FormattedMessage - defaultMessage="onboarding.create_project.azure.no_url.admin" - id="onboarding.create_project.azure.no_url.admin" - values={ + <AlmSettingsInstanceDropdown + almInstances={ + Array [ Object { - "alm": "onboarding.alm.azure", - "url": <ForwardRef(Link) - to={ - Object { - "pathname": "/admin/settings", - "search": "?category=almintegration", - } - } - > - settings.page - </ForwardRef(Link)>, - } - } - /> - </Alert> + "alm": "azure", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + /> </Fragment> `; @@ -198,11 +208,17 @@ exports[`should render correctly: setting missing url, not admin 1`] = ` </span> } /> - <Alert - variant="error" - > - onboarding.create_project.azure.no_url - </Alert> + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "azure", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + /> </Fragment> `; @@ -224,21 +240,17 @@ exports[`should render correctly: token form 1`] = ` </span> } /> - <div - className="display-flex-justify-center" - > - <AzurePersonalAccessTokenForm - almSetting={ + <AlmSettingsInstanceDropdown + almInstances={ + Array [ Object { "alm": "azure", "key": "key", "url": "https://azure.company.com", - } - } - onPersonalAccessTokenCreate={[MockFunction]} - submitting={false} - validationFailed={false} - /> - </div> + }, + ] + } + onChangeConfig={[MockFunction]} + /> </Fragment> `; 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 7d5f76c3837..a49fc0433bb 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 @@ -92,6 +92,7 @@ exports[`should render correctly for azure mode 1`] = ` id="create-project" > <AzureProjectCreate + almInstances={Array []} canAdmin={false} loadingBindings={true} location={ @@ -120,7 +121,6 @@ exports[`should render correctly for azure mode 1`] = ` "setRouteLeaveHook": [MockFunction], } } - settings={Array []} /> </div> </Fragment> diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/GitlabProjectCreateRenderer-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/GitlabProjectCreateRenderer-test.tsx.snap index 0fcab57ab4d..a84db1f9b28 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/GitlabProjectCreateRenderer-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/GitlabProjectCreateRenderer-test.tsx.snap @@ -17,6 +17,15 @@ exports[`should render correctly: invalid settings 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "gitlab", + "key": "key", + } + } + /> <PersonalAccessTokenForm almSetting={ Object { @@ -47,6 +56,15 @@ exports[`should render correctly: invalid settings, admin user 1`] = ` </span> } /> + <AlmSettingsInstanceDropdown + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "gitlab", + "key": "key", + } + } + /> <PersonalAccessTokenForm almSetting={ Object { @@ -77,38 +95,31 @@ exports[`should render correctly: loading 1`] = ` </span> } /> - <div - className="display-flex-column huge-spacer-bottom" - > - <label - className="spacer-bottom" - htmlFor="alm-config-selector" - > - alm.configuration.selector.label - </label> - <AlmSettingsInstanceSelector - classNames="abs-width-400" - initialValue="key" - inputId="alm-config-selector" - instances={ - Array [ - Object { - "alm": "gitlab", - "key": "key", - }, - Object { - "alm": "gitlab", - "key": "key", - }, - Object { - "alm": "github", - "key": "key", - }, - ] + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "gitlab", + "key": "key", + }, + Object { + "alm": "gitlab", + "key": "key", + }, + Object { + "alm": "github", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "gitlab", + "key": "key", } - onChange={[MockFunction]} - /> - </div> + } + /> <i className="spinner" /> @@ -132,38 +143,31 @@ exports[`should render correctly: pat form 1`] = ` </span> } /> - <div - className="display-flex-column huge-spacer-bottom" - > - <label - className="spacer-bottom" - htmlFor="alm-config-selector" - > - alm.configuration.selector.label - </label> - <AlmSettingsInstanceSelector - classNames="abs-width-400" - initialValue="key" - inputId="alm-config-selector" - instances={ - Array [ - Object { - "alm": "gitlab", - "key": "key", - }, - Object { - "alm": "gitlab", - "key": "key", - }, - Object { - "alm": "github", - "key": "key", - }, - ] + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "gitlab", + "key": "key", + }, + Object { + "alm": "gitlab", + "key": "key", + }, + Object { + "alm": "github", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "gitlab", + "key": "key", } - onChange={[MockFunction]} - /> - </div> + } + /> <PersonalAccessTokenForm almSetting={ Object { @@ -194,38 +198,31 @@ exports[`should render correctly: project selection form 1`] = ` </span> } /> - <div - className="display-flex-column huge-spacer-bottom" - > - <label - className="spacer-bottom" - htmlFor="alm-config-selector" - > - alm.configuration.selector.label - </label> - <AlmSettingsInstanceSelector - classNames="abs-width-400" - initialValue="key" - inputId="alm-config-selector" - instances={ - Array [ - Object { - "alm": "gitlab", - "key": "key", - }, - Object { - "alm": "gitlab", - "key": "key", - }, - Object { - "alm": "github", - "key": "key", - }, - ] + <AlmSettingsInstanceDropdown + almInstances={ + Array [ + Object { + "alm": "gitlab", + "key": "key", + }, + Object { + "alm": "gitlab", + "key": "key", + }, + Object { + "alm": "github", + "key": "key", + }, + ] + } + onChangeConfig={[MockFunction]} + selectedAlmInstance={ + Object { + "alm": "gitlab", + "key": "key", } - onChange={[MockFunction]} - /> - </div> + } + /> <GitlabProjectSelectionForm loadingMore={false} onImport={[MockFunction]} 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 3c342c2804e..a620bcb52a6 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 @@ -23,4 +23,4 @@ export const PROJECT_NAME_MAX_LEN = 255; export const DEFAULT_BBS_PAGE_SIZE = 25; -export const ALLOWED_MULTIPLE_CONFIGS = [AlmKeys.GitLab]; +export const ALLOWED_MULTIPLE_CONFIGS = [AlmKeys.GitLab, AlmKeys.Azure]; 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 fabc60c1c97..d53f11dff02 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 @@ -121,7 +121,7 @@ it('should filter alm bindings appropriately', async () => { wrapper = shallowRender(); await waitAndUpdate(wrapper); - expect(wrapper.state().boundAlms).toEqual([AlmKeys.GitLab]); + expect(wrapper.state().boundAlms).toEqual([AlmKeys.Azure, AlmKeys.GitLab]); }); function shallowRender(overrides: Partial<ProjectCreationMenu['props']> = {}) { diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index aa861ca230e..870ff352a71 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -3583,7 +3583,7 @@ onboarding.create_project.see_on_github=See project on GitHub onboarding.create_project.search_prompt=Search for projects onboarding.create_project.set_up=Set up -onboarding.create_project.azure.title=Which Azure DevOps repository do you want to set up? +onboarding.create_project.azure.title=Azure project onboarding onboarding.create_project.azure.no_projects=No projects could be fetched from Azure DevOps. Contact your system administrator, or {link}. onboarding.create_project.azure.search_results_for_project_X=Search results for "{0}" onboarding.create_project.azure.no_repositories=Could not fetch repositories for this project. Contact your system administrator, or {link}. |