Commit 559d89cf authored by Tim Zallmann's avatar Tim Zallmann

Merge branch '2934-create-new-project-re-add-project-name-field' into 'master'

Resolve "Create new project: Re-add project name field"

Closes #2934

See merge request gitlab-org/gitlab-ce!21386
parents 1d69d26f 03ab130e
......@@ -48,6 +48,16 @@ export const dasherize = str => str.replace(/[_\s]+/g, '-');
*/
export const slugify = str => str.trim().toLowerCase();
/**
* Replaces whitespaces with hyphens and converts to lower case
* @param {String} str
* @returns {String}
*/
export const slugifyWithHyphens = str => {
const regex = new RegExp(/\s+/, 'g');
return str.toLowerCase().replace(regex, '-');
};
/**
* Truncates given text
*
......
import $ from 'jquery';
import { getParameterValues } from '../lib/utils/url_utility';
import projectNew from './project_new';
export default () => {
const path = getParameterValues('path')[0];
const pathParam = getParameterValues('path')[0];
const nameParam = getParameterValues('name')[0];
const $projectPath = $('.js-path-name');
const $projectName = $('.js-project-name');
// get the path url and append it in the inputS
$('.js-path-name').val(path);
// get the path url and append it in the input
$projectPath.val(pathParam);
// get the project name from the URL and set it as input value
$projectName.val(nameParam);
// generate slug when project name changes
$projectName.keyup(() => projectNew.onProjectNameChange($projectName, $projectPath));
};
import $ from 'jquery';
import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils';
import { slugifyWithHyphens } from '../lib/utils/text_utility';
let hasUserDefinedProjectPath = false;
......@@ -29,18 +30,23 @@ const deriveProjectPathFromUrl = ($projectImportUrl) => {
}
};
const onProjectNameChange = ($projectNameInput, $projectPathInput) => {
const slug = slugifyWithHyphens($projectNameInput.val());
$projectPathInput.val(slug);
};
const bindEvents = () => {
const $newProjectForm = $('#new_project');
const $projectImportUrl = $('#project_import_url');
const $projectPath = $('#project_path');
const $projectPath = $('.tab-pane.active #project_path');
const $useTemplateBtn = $('.template-button > input');
const $projectFieldsForm = $('.project-fields-form');
const $selectedTemplateText = $('.selected-template');
const $changeTemplateBtn = $('.change-template');
const $selectedIcon = $('.selected-icon');
const $templateProjectNameInput = $('#template-project-name #project_path');
const $pushNewProjectTipTrigger = $('.push-new-project-tip');
const $projectTemplateButtons = $('.project-templates-buttons');
const $projectName = $('.tab-pane.active #project_name');
if ($newProjectForm.length !== 1) {
return;
......@@ -57,7 +63,8 @@ const bindEvents = () => {
$('.btn_import_gitlab_project').on('click', () => {
const importHref = $('a.btn_import_gitlab_project').attr('href');
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`);
$('.btn_import_gitlab_project')
.attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&name=${$projectName.val()}&path=${$projectPath.val()}`);
});
if ($pushNewProjectTipTrigger) {
......@@ -111,7 +118,15 @@ const bindEvents = () => {
const selectedTemplate = templates[value];
$selectedTemplateText.text(selectedTemplate.text);
$(selectedTemplate.icon).clone().addClass('d-block').appendTo($selectedIcon);
$templateProjectNameInput.focus();
const $activeTabProjectName = $('.tab-pane.active #project_name');
const $activeTabProjectPath = $('.tab-pane.active #project_path');
$activeTabProjectName.focus();
$activeTabProjectName
.keyup(() => {
onProjectNameChange($activeTabProjectName, $activeTabProjectPath);
hasUserDefinedProjectPath = $activeTabProjectPath.val().trim().length > 0;
});
}
$useTemplateBtn.on('change', chooseTemplate);
......@@ -131,9 +146,15 @@ const bindEvents = () => {
});
$projectImportUrl.keyup(() => deriveProjectPathFromUrl($projectImportUrl));
$projectName.keyup(() => {
onProjectNameChange($projectName, $projectPath);
hasUserDefinedProjectPath = $projectPath.val().trim().length > 0;
});
};
export default {
bindEvents,
deriveProjectPathFromUrl,
onProjectNameChange,
};
......@@ -8,8 +8,11 @@
= form_tag import_gitlab_project_path, class: 'new_project', multipart: true do
.row
.form-group.project-name.col-sm-12
= label_tag :name, _('Project name'), class: 'label-bold'
= text_field_tag :name, @name, placeholder: "My awesome project", class: "js-project-name form-control input-lg", autofocus: true, required: true
.form-group.col-12.col-sm-6
= label_tag :namespace_id, 'Project path', class: 'label-bold'
= label_tag :namespace_id, _('Project URL'), class: 'label-bold'
.form-group
.input-group
- if current_user.can_select_namespace?
......@@ -24,8 +27,8 @@
#{user_url(current_user.username)}/
= hidden_field_tag :namespace_id, value: current_user.namespace_id
.form-group.col-12.col-sm-6.project-path
= label_tag :path, _('Project name'), class: 'label-bold'
= text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, autofocus: true, required: true
= label_tag :path, _('Project slug'), class: 'label-bold'
= text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, required: true
.row
.form-group.col-md-12
......
......@@ -3,10 +3,13 @@
.row{ id: project_name_id }
= f.hidden_field :ci_cd_only, value: ci_cd_only
.form-group.project-name.col-sm-12
= f.label :name, class: 'label-bold' do
%span= _("Project name")
= f.text_field :name, placeholder: "My awesome project", class: "form-control input-lg", autofocus: true, required: true
.form-group.project-path.col-sm-6
= f.label :namespace_id, class: 'label-bold' do
%span
Project path
%span= s_("Project URL")
.input-group
- if current_user.can_select_namespace?
.input-group-prepend.has-tooltip{ title: root_url }
......@@ -27,13 +30,12 @@
= f.hidden_field :namespace_id, value: current_user.namespace_id
.form-group.project-path.col-sm-6
= f.label :path, class: 'label-bold' do
%span
Project name
= f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, autofocus: true, required: true
%span= _("Project slug")
= f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 2, required: true
- if current_user.can_create_group?
.form-text.text-muted
Want to house several dependent projects under the same namespace?
= link_to "Create a group", new_group_path
= link_to "Create a group.", new_group_path
.form-group
= f.label :description, class: 'label-bold' do
......
---
title: Re-add project name field on "Create new project" page
merge_request: 21386
author:
type: other
......@@ -4681,6 +4681,9 @@ msgstr ""
msgid "Project Badges"
msgstr ""
msgid "Project URL"
msgstr ""
msgid "Project access must be granted explicitly to each user."
msgstr ""
......@@ -4708,6 +4711,9 @@ msgstr ""
msgid "Project name"
msgstr ""
msgid "Project slug"
msgstr ""
msgid "ProjectActivityRSS|Subscribe"
msgstr ""
......
......@@ -20,7 +20,7 @@ describe 'Top Plus Menu', :js do
click_topmenuitem("New project")
expect(page).to have_content('Project path')
expect(page).to have_content('Project URL')
expect(page).to have_content('Project name')
end
......@@ -92,7 +92,7 @@ describe 'Top Plus Menu', :js do
find('.header-new-group-project a').click
end
expect(page).to have_content('Project path')
expect(page).to have_content('Project URL')
expect(page).to have_content('Project name')
end
end
......
......@@ -20,6 +20,7 @@ describe 'Import/Export - project import integration test', :js do
context 'when selecting the namespace' do
let(:user) { create(:admin) }
let!(:namespace) { user.namespace }
let(:project_name) { 'Test Project Name' + SecureRandom.hex }
let(:project_path) { 'test-project-path' + SecureRandom.hex }
context 'prefilled the path' do
......@@ -27,12 +28,13 @@ describe 'Import/Export - project import integration test', :js do
visit new_project_path
select2(namespace.id, from: '#project_namespace_id')
fill_in :project_name, with: project_name, visible: true
fill_in :project_path, with: project_path, visible: true
click_import_project_tab
click_link 'GitLab export'
expect(page).to have_content('Import an exported GitLab project')
expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=#{project_path}")
expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&name=#{ERB::Util.url_encode(project_name)}&path=#{project_path}")
attach_file('file', file)
click_on 'Import project'
......@@ -56,6 +58,7 @@ describe 'Import/Export - project import integration test', :js do
click_import_project_tab
click_link 'GitLab export'
fill_in :name, with: 'Test Project Name', visible: true
fill_in :path, with: 'test-project-path', visible: true
attach_file('file', file)
......@@ -74,7 +77,8 @@ describe 'Import/Export - project import integration test', :js do
visit new_project_path
select2(user.namespace.id, from: '#project_namespace_id')
fill_in :project_path, with: project.name, visible: true
fill_in :project_name, with: project.name, visible: true
fill_in :project_path, with: project.path, visible: true
click_import_project_tab
click_link 'GitLab export'
attach_file('file', file)
......
......@@ -12,8 +12,9 @@ describe 'New project' do
it 'shows "New project" page', :js do
visit new_project_path
expect(page).to have_content('Project path')
expect(page).to have_content('Project name')
expect(page).to have_content('Project URL')
expect(page).to have_content('Project slug')
find('#import-project-tab').click
......@@ -187,7 +188,7 @@ describe 'New project' do
collision_project = create(:project, name: 'test-name-collision', namespace: user.namespace)
fill_in 'project_import_url', with: collision_project.http_url_to_repo
fill_in 'project_path', with: collision_project.path
fill_in 'project_name', with: collision_project.name
click_on 'Create project'
......
......@@ -11,7 +11,7 @@ describe 'User creates a project', :js do
it 'creates a new project' do
visit(new_project_path)
fill_in(:project_path, with: 'Empty')
fill_in(:project_name, with: 'Empty')
page.within('#content-body') do
click_button('Create project')
......@@ -37,6 +37,7 @@ describe 'User creates a project', :js do
it 'creates a new project' do
visit(new_project_path)
fill_in :project_name, with: 'A Subgroup Project'
fill_in :project_path, with: 'a-subgroup-project'
page.find('.js-select-namespace').click
......@@ -46,7 +47,7 @@ describe 'User creates a project', :js do
click_button('Create project')
end
expect(page).to have_content("Project 'a-subgroup-project' was successfully created")
expect(page).to have_content("Project 'A Subgroup Project' was successfully created")
project = Project.last
......
......@@ -16,7 +16,7 @@ describe 'Project' do
it "allows creation from templates", :js do
find('#create-from-template-tab').click
find("label[for=#{template.name}]").click
fill_in("project_path", with: template.name)
fill_in("project_name", with: template.name)
page.within '#content-body' do
click_button "Create project"
......
......@@ -63,6 +63,12 @@ describe('text_utility', () => {
});
});
describe('slugifyWithHyphens', () => {
it('should replaces whitespaces with hyphens and convert to lower case', () => {
expect(textUtils.slugifyWithHyphens('My Input String')).toEqual('my-input-string');
});
});
describe('stripHtml', () => {
it('replaces html tag with the default replacement', () => {
expect(textUtils.stripHtml('This is a text with <p>html</p>.')).toEqual(
......
......@@ -4,12 +4,14 @@ import projectNew from '~/projects/project_new';
describe('New Project', () => {
let $projectImportUrl;
let $projectPath;
let $projectName;
beforeEach(() => {
setFixtures(`
<div class='toggle-import-form'>
<div class='import-url-data'>
<input id="project_import_url" />
<input id="project_name" />
<input id="project_path" />
</div>
</div>
......@@ -17,6 +19,7 @@ describe('New Project', () => {
$projectImportUrl = $('#project_import_url');
$projectPath = $('#project_path');
$projectName = $('#project_name');
});
describe('deriveProjectPathFromUrl', () => {
......@@ -129,4 +132,31 @@ describe('New Project', () => {
});
});
});
describe('deriveSlugFromProjectName', () => {
beforeEach(() => {
projectNew.bindEvents();
$projectName.val('').keyup();
});
it('converts project name to lower case and dash-limited slug', () => {
const dummyProjectName = 'My Awesome Project';
$projectName.val(dummyProjectName);
projectNew.onProjectNameChange($projectName, $projectPath);
expect($projectPath.val()).toEqual('my-awesome-project');
});
it('does not add additional dashes in the slug if the project name already contains dashes', () => {
const dummyProjectName = 'My-Dash-Delimited Awesome Project';
$projectName.val(dummyProjectName);
projectNew.onProjectNameChange($projectName, $projectPath);
expect($projectPath.val()).toEqual('my-dash-delimited-awesome-project');
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment