interface State { | interface State { | ||||
projectName: string; | projectName: string; | ||||
projectNameError?: string; | projectNameError?: string; | ||||
projectNameTouched?: boolean; | |||||
projectNameTouched: boolean; | |||||
projectKey: string; | projectKey: string; | ||||
projectKeyError?: string; | projectKeyError?: string; | ||||
projectKeyTouched?: boolean; | |||||
projectKeyTouched: boolean; | |||||
validatingProjectKey: boolean; | validatingProjectKey: boolean; | ||||
submitting: boolean; | submitting: boolean; | ||||
} | } | ||||
projectKey: '', | projectKey: '', | ||||
projectName: '', | projectName: '', | ||||
submitting: false, | submitting: false, | ||||
projectKeyTouched: false, | |||||
projectNameTouched: false, | |||||
validatingProjectKey: false | validatingProjectKey: false | ||||
}; | }; | ||||
this.checkFreeKey = debounce(this.checkFreeKey, 250); | this.checkFreeKey = debounce(this.checkFreeKey, 250); | ||||
validateName = (projectName: string) => { | validateName = (projectName: string) => { | ||||
if (projectName.length === 0) { | if (projectName.length === 0) { | ||||
return translate('onboarding.create_project.display_name.error.empty'); | return translate('onboarding.create_project.display_name.error.empty'); | ||||
} else if (projectName.length > PROJECT_NAME_MAX_LEN) { | |||||
return translate('onboarding.create_project.display_name.error.too_long'); | |||||
} | } | ||||
return undefined; | return undefined; | ||||
}; | }; | ||||
const { branchesEnabled } = this.props; | const { branchesEnabled } = this.props; | ||||
const touched = !!(projectKeyTouched || projectNameTouched); | const touched = !!(projectKeyTouched || projectNameTouched); | ||||
const projectNameIsInvalid = touched && projectNameError !== undefined; | |||||
const projectNameIsValid = touched && projectNameError === undefined; | |||||
const projectNameIsInvalid = projectNameTouched && projectNameError !== undefined; | |||||
const projectNameIsValid = projectNameTouched && projectNameError === undefined; | |||||
return ( | return ( | ||||
<> | <> |
/* | |||||
* 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 { shallow } from 'enzyme'; | |||||
import * as React from 'react'; | |||||
import CreateProjectPageHeader, { CreateProjectPageHeaderProps } from '../CreateProjectPageHeader'; | |||||
it('should render correctly', () => { | |||||
expect(shallowRender()).toMatchSnapshot('default'); | |||||
expect(shallowRender({ additionalActions: 'Bar' })).toMatchSnapshot('additional content'); | |||||
}); | |||||
function shallowRender(props: Partial<CreateProjectPageHeaderProps> = {}) { | |||||
return shallow<CreateProjectPageHeaderProps>(<CreateProjectPageHeader title="Foo" {...props} />); | |||||
} |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
import { shallow } from 'enzyme'; | |||||
import { screen } from '@testing-library/react'; | |||||
import userEvent from '@testing-library/user-event'; | |||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { createProject, doesComponentExists } from '../../../../api/components'; | import { createProject, doesComponentExists } from '../../../../api/components'; | ||||
import ProjectKeyInput from '../../../../components/common/ProjectKeyInput'; | |||||
import { SubmitButton } from '../../../../components/controls/buttons'; | |||||
import ValidationInput from '../../../../components/controls/ValidationInput'; | |||||
import { validateProjectKey } from '../../../../helpers/projects'; | |||||
import { change, mockEvent, submit, waitAndUpdate } from '../../../../helpers/testUtils'; | |||||
import { ProjectKeyValidationResult } from '../../../../types/component'; | |||||
import { PROJECT_NAME_MAX_LEN } from '../constants'; | |||||
import { renderComponent } from '../../../../helpers/testReactTestingUtils'; | |||||
import ManualProjectCreate from '../ManualProjectCreate'; | import ManualProjectCreate from '../ManualProjectCreate'; | ||||
jest.mock('../../../../api/components', () => ({ | jest.mock('../../../../api/components', () => ({ | ||||
.mockImplementation(({ component }) => Promise.resolve(component === 'exists')) | .mockImplementation(({ component }) => Promise.resolve(component === 'exists')) | ||||
})); | })); | ||||
jest.mock('../../../../helpers/projects', () => { | |||||
const { PROJECT_KEY_INVALID_CHARACTERS } = jest.requireActual('../../../../helpers/projects'); | |||||
return { | |||||
validateProjectKey: jest.fn(() => ProjectKeyValidationResult.Valid), | |||||
PROJECT_KEY_INVALID_CHARACTERS | |||||
}; | |||||
}); | |||||
beforeEach(() => { | beforeEach(() => { | ||||
jest.clearAllMocks(); | jest.clearAllMocks(); | ||||
}); | }); | ||||
it('should render correctly', () => { | |||||
expect(shallowRender()).toMatchSnapshot(); | |||||
const wrapper = shallowRender(); | |||||
wrapper.instance().handleProjectNameChange('My new awesome app'); | |||||
expect(wrapper).toMatchSnapshot('with form filled'); | |||||
expect(shallowRender({ branchesEnabled: true })).toMatchSnapshot('with branches enabled'); | |||||
it('should show branch information', async () => { | |||||
renderManualProjectCreate({ branchesEnabled: true }); | |||||
expect( | |||||
await screen.findByText('onboarding.create_project.pr_decoration.information') | |||||
).toBeInTheDocument(); | |||||
}); | }); | ||||
it('should correctly create a project', async () => { | |||||
const onProjectCreate = jest.fn(); | |||||
const wrapper = shallowRender({ onProjectCreate }); | |||||
wrapper | |||||
.find(ProjectKeyInput) | |||||
.props() | |||||
.onProjectKeyChange(mockEvent({ currentTarget: { value: 'bar' } })); | |||||
change(wrapper.find('input#project-name'), 'Bar'); | |||||
expect(wrapper.find(SubmitButton).props().disabled).toBe(false); | |||||
expect(validateProjectKey).toBeCalledWith('bar'); | |||||
expect(doesComponentExists).toBeCalledWith({ component: 'bar' }); | |||||
submit(wrapper.find('form')); | |||||
expect(createProject).toBeCalledWith({ | |||||
project: 'bar', | |||||
name: 'Bar' | |||||
}); | |||||
await waitAndUpdate(wrapper); | |||||
expect(onProjectCreate).toBeCalledWith('bar'); | |||||
}); | |||||
it('should validate form input', async () => { | |||||
const user = userEvent.setup(); | |||||
renderManualProjectCreate(); | |||||
it('should not display any status when the name is not defined', () => { | |||||
const wrapper = shallowRender(); | |||||
const projectNameInput = wrapper.find(ValidationInput); | |||||
expect(projectNameInput.props().isInvalid).toBe(false); | |||||
expect(projectNameInput.props().isValid).toBe(false); | |||||
}); | |||||
it('should have an error when the key is invalid', () => { | |||||
(validateProjectKey as jest.Mock).mockReturnValueOnce(ProjectKeyValidationResult.TooLong); | |||||
const wrapper = shallowRender(); | |||||
wrapper.instance().handleProjectKeyChange(''); | |||||
expect(wrapper.find(ProjectKeyInput).props().error).toBe( | |||||
`onboarding.create_project.project_key.error.${ProjectKeyValidationResult.TooLong}` | |||||
// All input valid | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.display_name field_required' | |||||
}) | |||||
); | ); | ||||
await user.keyboard('test'); | |||||
expect( | |||||
screen.getByRole('textbox', { name: 'onboarding.create_project.project_key field_required' }) | |||||
).toHaveValue('test'); | |||||
expect(screen.getByRole('button', { name: 'set_up' })).toBeEnabled(); | |||||
// Sanitize the key | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.display_name field_required' | |||||
}) | |||||
); | |||||
await user.keyboard('{Control>}a{/Control}This is not a key%^$'); | |||||
expect( | |||||
screen.getByRole('textbox', { name: 'onboarding.create_project.project_key field_required' }) | |||||
).toHaveValue('This-is-not-a-key-'); | |||||
// Clear name | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.display_name field_required' | |||||
}) | |||||
); | |||||
await user.keyboard('{Control>}a{/Control}{Backspace}'); | |||||
expect( | |||||
screen.getByRole('textbox', { name: 'onboarding.create_project.project_key field_required' }) | |||||
).toHaveValue(''); | |||||
expect( | |||||
screen.getByText('onboarding.create_project.display_name.error.empty') | |||||
).toBeInTheDocument(); | |||||
expect(screen.getByRole('button', { name: 'set_up' })).toBeDisabled(); | |||||
// Only key | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.project_key field_required' | |||||
}) | |||||
); | |||||
await user.keyboard('awsome-key'); | |||||
expect( | |||||
screen.getByRole('textbox', { name: 'onboarding.create_project.display_name field_required' }) | |||||
).toHaveValue(''); | |||||
expect(screen.getByLabelText('valid_input')).toBeInTheDocument(); | |||||
expect( | |||||
screen.getByText('onboarding.create_project.display_name.error.empty') | |||||
).toBeInTheDocument(); | |||||
// Invalid key | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.project_key field_required' | |||||
}) | |||||
); | |||||
await user.keyboard('{Control>}a{/Control}123'); | |||||
expect( | |||||
await screen.findByText('onboarding.create_project.project_key.error.only_digits') | |||||
).toBeInTheDocument(); | |||||
await user.keyboard('{Control>}a{/Control}@'); | |||||
expect( | |||||
await screen.findByText('onboarding.create_project.project_key.error.invalid_char') | |||||
).toBeInTheDocument(); | |||||
await user.keyboard('{Control>}a{/Control}exists'); | |||||
expect( | |||||
await screen.findByText('onboarding.create_project.project_key.taken') | |||||
).toBeInTheDocument(); | |||||
}); | }); | ||||
it('should have an error when the key already exists', async () => { | |||||
const wrapper = shallowRender(); | |||||
wrapper.instance().handleProjectKeyChange('exists', true); | |||||
await waitAndUpdate(wrapper); | |||||
expect(wrapper.state().projectKeyError).toBe('onboarding.create_project.project_key.taken'); | |||||
}); | |||||
it('should ignore promise return if value has been changed in the meantime', async () => { | |||||
(validateProjectKey as jest.Mock) | |||||
.mockReturnValueOnce(ProjectKeyValidationResult.Valid) | |||||
.mockReturnValueOnce(ProjectKeyValidationResult.InvalidChar); | |||||
const wrapper = shallowRender(); | |||||
const instance = wrapper.instance(); | |||||
instance.handleProjectKeyChange('exists', true); | |||||
instance.handleProjectKeyChange('exists%', true); | |||||
await waitAndUpdate(wrapper); | |||||
it('should submit form input', async () => { | |||||
const user = userEvent.setup(); | |||||
const onProjectCreate = jest.fn(); | |||||
renderManualProjectCreate({ onProjectCreate }); | |||||
expect(wrapper.state().projectKeyTouched).toBe(true); | |||||
expect(wrapper.state().projectKeyError).toBe( | |||||
`onboarding.create_project.project_key.error.${ProjectKeyValidationResult.InvalidChar}` | |||||
// All input valid | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.display_name field_required' | |||||
}) | |||||
); | ); | ||||
await user.keyboard('test'); | |||||
await user.click(screen.getByRole('button', { name: 'set_up' })); | |||||
expect(createProject).toHaveBeenCalledWith({ name: 'test', project: 'test' }); | |||||
expect(onProjectCreate).toBeCalled(); | |||||
}); | }); | ||||
it('should autofill the key based on the name, and sanitize it', () => { | |||||
const wrapper = shallowRender(); | |||||
it('should handle create failure', async () => { | |||||
const user = userEvent.setup(); | |||||
(createProject as jest.Mock).mockRejectedValueOnce({}); | |||||
const onProjectCreate = jest.fn(); | |||||
renderManualProjectCreate({ onProjectCreate }); | |||||
wrapper.instance().handleProjectNameChange('newName', true); | |||||
expect(wrapper.state().projectKey).toBe('newName'); | |||||
// All input valid | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.display_name field_required' | |||||
}) | |||||
); | |||||
await user.keyboard('test'); | |||||
await user.click(screen.getByRole('button', { name: 'set_up' })); | |||||
wrapper.instance().handleProjectNameChange('my invalid +"*ç%&/()= name', true); | |||||
expect(wrapper.state().projectKey).toBe('my-invalid-name'); | |||||
expect(onProjectCreate).not.toHaveBeenCalled(); | |||||
}); | }); | ||||
it.each([ | |||||
['empty', ''], | |||||
['too_long', new Array(PROJECT_NAME_MAX_LEN + 1).fill('a').join('')] | |||||
])('should have an error when the name is %s', (errorSuffix: string, projectName: string) => { | |||||
const wrapper = shallowRender(); | |||||
it('should handle component exists failure', async () => { | |||||
const user = userEvent.setup(); | |||||
(doesComponentExists as jest.Mock).mockRejectedValueOnce({}); | |||||
const onProjectCreate = jest.fn(); | |||||
renderManualProjectCreate({ onProjectCreate }); | |||||
wrapper.instance().handleProjectNameChange(projectName, true); | |||||
expect(wrapper.find(ValidationInput).props().isInvalid).toBe(true); | |||||
expect(wrapper.state().projectNameError).toBe( | |||||
`onboarding.create_project.display_name.error.${errorSuffix}` | |||||
// All input valid | |||||
await user.click( | |||||
await screen.findByRole('textbox', { | |||||
name: 'onboarding.create_project.display_name field_required' | |||||
}) | |||||
); | ); | ||||
await user.keyboard('test'); | |||||
expect( | |||||
screen.getByRole('textbox', { name: 'onboarding.create_project.display_name field_required' }) | |||||
).toHaveValue('test'); | |||||
}); | }); | ||||
function shallowRender(props: Partial<ManualProjectCreate['props']> = {}) { | |||||
return shallow<ManualProjectCreate>( | |||||
function renderManualProjectCreate(props: Partial<ManualProjectCreate['props']> = {}) { | |||||
renderComponent( | |||||
<ManualProjectCreate branchesEnabled={false} onProjectCreate={jest.fn()} {...props} /> | <ManualProjectCreate branchesEnabled={false} onProjectCreate={jest.fn()} {...props} /> | ||||
); | ); | ||||
} | } |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly: additional content 1`] = ` | |||||
<header | |||||
className="huge-spacer-bottom bordered-bottom overflow-hidden" | |||||
> | |||||
<h1 | |||||
className="pull-left huge big-spacer-bottom" | |||||
> | |||||
Foo | |||||
</h1> | |||||
Bar | |||||
</header> | |||||
`; | |||||
exports[`should render correctly: default 1`] = ` | |||||
<header | |||||
className="huge-spacer-bottom bordered-bottom overflow-hidden" | |||||
> | |||||
<h1 | |||||
className="pull-left huge big-spacer-bottom" | |||||
> | |||||
Foo | |||||
</h1> | |||||
</header> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<Fragment> | |||||
<CreateProjectPageHeader | |||||
title="onboarding.create_project.setup_manually" | |||||
/> | |||||
<div | |||||
className="create-project-manual" | |||||
> | |||||
<div | |||||
className="flex-1 huge-spacer-right" | |||||
> | |||||
<form | |||||
className="manual-project-create" | |||||
onSubmit={[Function]} | |||||
> | |||||
<MandatoryFieldsExplanation | |||||
className="big-spacer-bottom" | |||||
/> | |||||
<ValidationInput | |||||
className="form-field" | |||||
description="onboarding.create_project.display_name.description" | |||||
id="project-name" | |||||
isInvalid={false} | |||||
isValid={false} | |||||
label="onboarding.create_project.display_name" | |||||
required={true} | |||||
> | |||||
<input | |||||
autoFocus={true} | |||||
className="input-super-large" | |||||
id="project-name" | |||||
maxLength={255} | |||||
minLength={1} | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="" | |||||
/> | |||||
</ValidationInput> | |||||
<ProjectKeyInput | |||||
label="onboarding.create_project.project_key" | |||||
onProjectKeyChange={[Function]} | |||||
projectKey="" | |||||
touched={false} | |||||
validating={false} | |||||
/> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
set_up | |||||
</SubmitButton> | |||||
<DeferredSpinner | |||||
className="spacer-left" | |||||
loading={false} | |||||
/> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
</Fragment> | |||||
`; | |||||
exports[`should render correctly: with branches enabled 1`] = ` | |||||
<Fragment> | |||||
<CreateProjectPageHeader | |||||
title="onboarding.create_project.setup_manually" | |||||
/> | |||||
<div | |||||
className="create-project-manual" | |||||
> | |||||
<div | |||||
className="flex-1 huge-spacer-right" | |||||
> | |||||
<form | |||||
className="manual-project-create" | |||||
onSubmit={[Function]} | |||||
> | |||||
<MandatoryFieldsExplanation | |||||
className="big-spacer-bottom" | |||||
/> | |||||
<ValidationInput | |||||
className="form-field" | |||||
description="onboarding.create_project.display_name.description" | |||||
id="project-name" | |||||
isInvalid={false} | |||||
isValid={false} | |||||
label="onboarding.create_project.display_name" | |||||
required={true} | |||||
> | |||||
<input | |||||
autoFocus={true} | |||||
className="input-super-large" | |||||
id="project-name" | |||||
maxLength={255} | |||||
minLength={1} | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="" | |||||
/> | |||||
</ValidationInput> | |||||
<ProjectKeyInput | |||||
label="onboarding.create_project.project_key" | |||||
onProjectKeyChange={[Function]} | |||||
projectKey="" | |||||
touched={false} | |||||
validating={false} | |||||
/> | |||||
<SubmitButton | |||||
disabled={true} | |||||
> | |||||
set_up | |||||
</SubmitButton> | |||||
<DeferredSpinner | |||||
className="spacer-left" | |||||
loading={false} | |||||
/> | |||||
</form> | |||||
<Alert | |||||
className="big-spacer-top" | |||||
display="inline" | |||||
variant="info" | |||||
> | |||||
onboarding.create_project.pr_decoration.information | |||||
</Alert> | |||||
</div> | |||||
</div> | |||||
</Fragment> | |||||
`; | |||||
exports[`should render correctly: with form filled 1`] = ` | |||||
<Fragment> | |||||
<CreateProjectPageHeader | |||||
title="onboarding.create_project.setup_manually" | |||||
/> | |||||
<div | |||||
className="create-project-manual" | |||||
> | |||||
<div | |||||
className="flex-1 huge-spacer-right" | |||||
> | |||||
<form | |||||
className="manual-project-create" | |||||
onSubmit={[Function]} | |||||
> | |||||
<MandatoryFieldsExplanation | |||||
className="big-spacer-bottom" | |||||
/> | |||||
<ValidationInput | |||||
className="form-field" | |||||
description="onboarding.create_project.display_name.description" | |||||
id="project-name" | |||||
isInvalid={false} | |||||
isValid={false} | |||||
label="onboarding.create_project.display_name" | |||||
required={true} | |||||
> | |||||
<input | |||||
autoFocus={true} | |||||
className="input-super-large" | |||||
id="project-name" | |||||
maxLength={255} | |||||
minLength={1} | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="My new awesome app" | |||||
/> | |||||
</ValidationInput> | |||||
<ProjectKeyInput | |||||
label="onboarding.create_project.project_key" | |||||
onProjectKeyChange={[Function]} | |||||
projectKey="My-new-awesome-app" | |||||
touched={false} | |||||
validating={true} | |||||
/> | |||||
<SubmitButton | |||||
disabled={false} | |||||
> | |||||
set_up | |||||
</SubmitButton> | |||||
<DeferredSpinner | |||||
className="spacer-left" | |||||
loading={false} | |||||
/> | |||||
</form> | |||||
</div> | |||||
</div> | |||||
</Fragment> | |||||
`; |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { translate } from '../../helpers/l10n'; | |||||
import AlertErrorIcon from '../icons/AlertErrorIcon'; | import AlertErrorIcon from '../icons/AlertErrorIcon'; | ||||
import AlertSuccessIcon from '../icons/AlertSuccessIcon'; | import AlertSuccessIcon from '../icons/AlertSuccessIcon'; | ||||
import MandatoryFieldMarker from '../ui/MandatoryFieldMarker'; | import MandatoryFieldMarker from '../ui/MandatoryFieldMarker'; | ||||
childrenWithStatus = ( | childrenWithStatus = ( | ||||
<> | <> | ||||
{children} | {children} | ||||
{isValid && <AlertSuccessIcon className="spacer-left text-middle" />} | |||||
{isValid && ( | |||||
<AlertSuccessIcon | |||||
ariaLabel={translate('valid_input')} | |||||
className="spacer-left text-middle" | |||||
/> | |||||
)} | |||||
{isInvalid && <AlertErrorIcon className="spacer-left text-middle" />} | {isInvalid && <AlertErrorIcon className="spacer-left text-middle" />} | ||||
{hasError && <span className="little-spacer-left text-danger text-middle">{error}</span>} | {hasError && <span className="little-spacer-left text-danger text-middle">{error}</span>} | ||||
</> | </> | ||||
childrenWithStatus = ( | childrenWithStatus = ( | ||||
<> | <> | ||||
{children} | {children} | ||||
{isValid && <AlertSuccessIcon className="spacer-left text-middle" />} | |||||
{isValid && ( | |||||
<AlertSuccessIcon | |||||
ariaLabel={translate('valid_input')} | |||||
className="spacer-left text-middle" | |||||
/> | |||||
)} | |||||
<div className="spacer-top"> | <div className="spacer-top"> | ||||
{isInvalid && <AlertErrorIcon className="text-middle" />} | {isInvalid && <AlertErrorIcon className="text-middle" />} | ||||
{hasError && <span className="little-spacer-left text-danger text-middle">{error}</span>} | {hasError && <span className="little-spacer-left text-danger text-middle">{error}</span>} |
> | > | ||||
<div /> | <div /> | ||||
<AlertSuccessIcon | <AlertSuccessIcon | ||||
ariaLabel="valid_input" | |||||
className="spacer-left text-middle" | className="spacer-left text-middle" | ||||
/> | /> | ||||
</div> | </div> | ||||
> | > | ||||
<div /> | <div /> | ||||
<AlertSuccessIcon | <AlertSuccessIcon | ||||
ariaLabel="valid_input" | |||||
className="spacer-left text-middle" | className="spacer-left text-middle" | ||||
/> | /> | ||||
</div> | </div> |
worst=Worst | worst=Worst | ||||
yes=Yes | yes=Yes | ||||
no=No | no=No | ||||
valid_input=Valid input | |||||
onboarding.create_project.project_key.taken=This project key is already taken. | onboarding.create_project.project_key.taken=This project key is already taken. | ||||
onboarding.create_project.display_name=Project display name | onboarding.create_project.display_name=Project display name | ||||
onboarding.create_project.display_name.error.empty=The display name is required. | onboarding.create_project.display_name.error.empty=The display name is required. | ||||
onboarding.create_project.display_name.error.too_long=The display name is too long. | |||||
onboarding.create_project.display_name.description=Up to 255 characters. Some scanners might override the value you provide. | onboarding.create_project.display_name.description=Up to 255 characters. Some scanners might override the value you provide. | ||||
onboarding.create_project.pr_decoration.information=Manually created projects won’t benefit from the features associated with DevOps Platforms integration unless you configure them in the project settings. | onboarding.create_project.pr_decoration.information=Manually created projects won’t benefit from the features associated with DevOps Platforms integration unless you configure them in the project settings. | ||||
onboarding.create_project.repository_imported=Already set up | onboarding.create_project.repository_imported=Already set up |