Преглед на файлове

SONAR-17589 Allow project onboarding when multiple Azure integrations are configured

tags/9.8.0.63668
Kevin Silva преди 1 година
родител
ревизия
a292eb339f
променени са 15 файла, в които са добавени 312 реда и са изтрити 220 реда
  1. 51
    0
      server/sonar-web/src/main/js/apps/create/project/AlmSettingsInstanceDropdown.tsx
  2. 35
    32
      server/sonar-web/src/main/js/apps/create/project/AzureProjectCreate.tsx
  3. 19
    9
      server/sonar-web/src/main/js/apps/create/project/AzureProjectCreateRenderer.tsx
  4. 1
    1
      server/sonar-web/src/main/js/apps/create/project/CreateProjectPage.tsx
  5. 6
    15
      server/sonar-web/src/main/js/apps/create/project/GitlabProjectCreateRenderer.tsx
  6. 3
    3
      server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreate-test.tsx
  7. 24
    5
      server/sonar-web/src/main/js/apps/create/project/__tests__/AzureProjectCreateRenderer-test.tsx
  8. 1
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/CreateProjectModeSelection-test.tsx
  9. 10
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreate-test.tsx.snap
  10. 68
    56
      server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/AzureProjectCreateRenderer-test.tsx.snap
  11. 1
    1
      server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
  12. 90
    93
      server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/GitlabProjectCreateRenderer-test.tsx.snap
  13. 1
    1
      server/sonar-web/src/main/js/apps/create/project/constants.ts
  14. 1
    1
      server/sonar-web/src/main/js/apps/projects/components/__tests__/ProjectCreationMenu-test.tsx
  15. 1
    1
      sonar-core/src/main/resources/org/sonar/l10n/core.properties

+ 51
- 0
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}
</>
);
}

+ 35
- 32
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}
/>
);
}

+ 19
- 9
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}

+ 1
- 1
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}
/>
);
}

+ 6
- 15
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" />}


+ 3
- 3
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}
/>
);

+ 24
- 5
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}
/>
);

+ 1
- 1
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();

+ 10
- 1
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",

+ 68
- 56
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>
`;

+ 1
- 1
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>

+ 90
- 93
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]}

+ 1
- 1
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];

+ 1
- 1
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']> = {}) {

+ 1
- 1
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}.

Loading…
Отказ
Запис