aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2019-05-23 17:55:22 +0200
committerSonarTech <sonartech@sonarsource.com>2019-05-29 20:21:14 +0200
commit8bb9de894171df87587f76d3b6829514f79ffff1 (patch)
treee94972c91cd1001d3e2cb112c97dffad908615c1 /server
parent8a6f82e51442fd43274741fd364a486379ab6422 (diff)
downloadsonarqube-8bb9de894171df87587f76d3b6829514f79ffff1.tar.gz
sonarqube-8bb9de894171df87587f76d3b6829514f79ffff1.zip
SONAR-12025 Allow spaces to be typed in project name
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/ProjectKeyInput.tsx23
-rw-r--r--server/sonar-web/src/main/js/apps/create/components/__tests__/ProjectKeyInput-test.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/ManualProjectCreate.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/create/project/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap2
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