diff options
author | Jeremy Davis <jeremy.davis@sonarsource.com> | 2019-05-23 17:55:22 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-05-29 20:21:14 +0200 |
commit | 8bb9de894171df87587f76d3b6829514f79ffff1 (patch) | |
tree | e94972c91cd1001d3e2cb112c97dffad908615c1 /server | |
parent | 8a6f82e51442fd43274741fd364a486379ab6422 (diff) | |
download | sonarqube-8bb9de894171df87587f76d3b6829514f79ffff1.tar.gz sonarqube-8bb9de894171df87587f76d3b6829514f79ffff1.zip |
SONAR-12025 Allow spaces to be typed in project name
Diffstat (limited to 'server')
4 files changed, 31 insertions, 33 deletions
diff --git a/server/sonar-web/src/main/js/apps/create/components/ProjectKeyInput.tsx b/server/sonar-web/src/main/js/apps/create/components/ProjectKeyInput.tsx index 424be3e19cb..f347217665e 100644 --- a/server/sonar-web/src/main/js/apps/create/components/ProjectKeyInput.tsx +++ b/server/sonar-web/src/main/js/apps/create/components/ProjectKeyInput.tsx @@ -26,7 +26,7 @@ import { translate } from '../../../helpers/l10n'; interface Props { className?: string; - initialValue?: string; + value: string; onChange: (value: string | undefined) => void; } @@ -34,22 +34,20 @@ interface State { error?: string; touched: boolean; validating: boolean; - value: string; } export default class ProjectKeyInput extends React.PureComponent<Props, State> { mounted = false; constructor(props: Props) { super(props); - this.state = { error: undefined, touched: false, validating: false, value: '' }; + this.state = { error: undefined, touched: false, validating: false }; this.checkFreeKey = debounce(this.checkFreeKey, 250); } componentDidMount() { this.mounted = true; - if (this.props.initialValue !== undefined) { - this.setState({ value: this.props.initialValue }); - this.validateKey(this.props.initialValue); + if (this.props.value) { + this.validateKey(this.props.value); } } @@ -61,32 +59,30 @@ export default class ProjectKeyInput extends React.PureComponent<Props, State> { this.setState({ validating: true }); return doesComponentExists({ component: key }) .then(alreadyExist => { - if (this.mounted) { + if (this.mounted && key === this.props.value) { if (!alreadyExist) { this.setState({ error: undefined, validating: false }); - this.props.onChange(key); } else { this.setState({ error: translate('onboarding.create_project.project_key.taken'), touched: true, validating: false }); - this.props.onChange(undefined); } } }) .catch(() => { - if (this.mounted) { + if (this.mounted && key === this.props.value) { this.setState({ error: undefined, validating: false }); - this.props.onChange(key); } }); }; handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { const { value } = event.currentTarget; - this.setState({ touched: true, value }); + this.setState({ touched: true }); this.validateKey(value); + this.props.onChange(value); }; validateKey(key: string) { @@ -95,7 +91,6 @@ export default class ProjectKeyInput extends React.PureComponent<Props, State> { error: translate('onboarding.create_project.project_key.error'), touched: true }); - this.props.onChange(undefined); } else { this.checkFreeKey(key); } @@ -126,7 +121,7 @@ export default class ProjectKeyInput extends React.PureComponent<Props, State> { minLength={1} onChange={this.handleChange} type="text" - value={this.state.value} + value={this.props.value} /> </ValidationInput> ); diff --git a/server/sonar-web/src/main/js/apps/create/components/__tests__/ProjectKeyInput-test.tsx b/server/sonar-web/src/main/js/apps/create/components/__tests__/ProjectKeyInput-test.tsx index f321e776723..4b47eaef943 100644 --- a/server/sonar-web/src/main/js/apps/create/components/__tests__/ProjectKeyInput-test.tsx +++ b/server/sonar-web/src/main/js/apps/create/components/__tests__/ProjectKeyInput-test.tsx @@ -20,19 +20,18 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import ProjectKeyInput from '../ProjectKeyInput'; -import { doesComponentExists } from '../../../../api/components'; import { waitAndUpdate } from '../../../../helpers/testUtils'; +jest.useFakeTimers(); + jest.mock('../../../../api/components', () => ({ - doesComponentExists: jest.fn().mockResolvedValue(false) + doesComponentExists: jest + .fn() + .mockImplementation(({ component }) => Promise.resolve(component === 'exists')) })); -beforeEach(() => { - (doesComponentExists as jest.Mock<any>).mockClear(); -}); - it('should render correctly', async () => { - const wrapper = shallow(<ProjectKeyInput initialValue="key" onChange={jest.fn()} />); + const wrapper = shallow(<ProjectKeyInput onChange={jest.fn()} value="key" />); expect(wrapper).toMatchSnapshot(); wrapper.setState({ touched: true }); await waitAndUpdate(wrapper); @@ -40,23 +39,23 @@ it('should render correctly', async () => { }); it('should not display any status when the key is not defined', async () => { - const wrapper = shallow(<ProjectKeyInput onChange={jest.fn()} />); + const wrapper = shallow(<ProjectKeyInput onChange={jest.fn()} value="" />); await waitAndUpdate(wrapper); expect(wrapper.find('ValidationInput').prop('isInvalid')).toBe(false); expect(wrapper.find('ValidationInput').prop('isValid')).toBe(false); }); it('should have an error when the key is invalid', async () => { - const wrapper = shallow( - <ProjectKeyInput initialValue="KEy-with#speci@l_char" onChange={jest.fn()} /> - ); + const wrapper = shallow(<ProjectKeyInput onChange={jest.fn()} value="KEy-with#speci@l_char" />); await waitAndUpdate(wrapper); expect(wrapper.find('ValidationInput').prop('isInvalid')).toBe(true); }); it('should have an error when the key already exists', async () => { - (doesComponentExists as jest.Mock<any>).mockResolvedValue(true); - const wrapper = shallow(<ProjectKeyInput initialValue="" onChange={jest.fn()} />); + const wrapper = shallow(<ProjectKeyInput onChange={jest.fn()} value="exists" />); await waitAndUpdate(wrapper); + + jest.runAllTimers(); + await new Promise(setImmediate); expect(wrapper.find('ValidationInput').prop('isInvalid')).toBe(true); }); diff --git a/server/sonar-web/src/main/js/apps/create/project/ManualProjectCreate.tsx b/server/sonar-web/src/main/js/apps/create/project/ManualProjectCreate.tsx index ad302695458..d23090555d9 100644 --- a/server/sonar-web/src/main/js/apps/create/project/ManualProjectCreate.tsx +++ b/server/sonar-web/src/main/js/apps/create/project/ManualProjectCreate.tsx @@ -40,9 +40,9 @@ interface Props { } interface State { - projectName?: string; + projectName: string; projectNameChanged: boolean; - projectKey?: string; + projectKey: string; selectedOrganization?: T.Organization; selectedVisibility?: T.Visibility; submitting: boolean; @@ -56,6 +56,8 @@ export default class ManualProjectCreate extends React.PureComponent<Props, Stat constructor(props: Props) { super(props); this.state = { + projectKey: '', + projectName: '', projectNameChanged: false, selectedOrganization: this.getInitialSelectedOrganization(props), submitting: false @@ -104,7 +106,7 @@ export default class ManualProjectCreate extends React.PureComponent<Props, Stat this.setState({ submitting: true }); createProject({ project: state.projectKey, - name: state.projectName || state.projectKey, + name: (state.projectName || state.projectKey).trim(), organization: state.selectedOrganization && state.selectedOrganization.key, visibility: this.state.selectedVisibility }).then( @@ -150,11 +152,11 @@ export default class ManualProjectCreate extends React.PureComponent<Props, Stat }; handleProjectNameChange = (event: React.ChangeEvent<HTMLInputElement>) => { - const projectName = event.currentTarget.value.trim(); + const projectName = event.currentTarget.value; this.setState({ projectName, projectNameChanged: true }); }; - handleProjectKeyChange = (projectKey?: string) => { + handleProjectKeyChange = (projectKey: string) => { this.setState(state => ({ projectKey, projectName: state.projectNameChanged ? state.projectName : projectKey || '' @@ -182,8 +184,8 @@ export default class ManualProjectCreate extends React.PureComponent<Props, Stat )} <ProjectKeyInput className="form-field" - initialValue={this.state.projectKey} onChange={this.handleProjectKeyChange} + value={this.state.projectKey} /> <div className="form-field"> <label htmlFor="project-name"> diff --git a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap index c44ed293cfb..3f8d2aaee08 100644 --- a/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap @@ -31,6 +31,7 @@ exports[`should render correctly 1`] = ` <ProjectKeyInput className="form-field" onChange={[Function]} + value="" /> <div className="form-field" @@ -65,6 +66,7 @@ exports[`should render correctly 1`] = ` minLength={1} onChange={[Function]} type="text" + value="" /> </div> <div |