diff options
-rw-r--r-- | app/assets/javascripts/lib/utils/common_utils.js | 10 | ||||
-rw-r--r-- | app/assets/javascripts/main.js | 10 | ||||
-rw-r--r-- | app/assets/javascripts/projects/project_new.js | 31 | ||||
-rw-r--r-- | app/assets/stylesheets/framework/typography.scss | 4 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/projects.scss | 6 | ||||
-rw-r--r-- | app/helpers/projects_helper.rb | 11 | ||||
-rw-r--r-- | app/views/projects/_new_project_push_tip.html.haml | 11 | ||||
-rw-r--r-- | app/views/projects/new.html.haml | 7 | ||||
-rw-r--r-- | doc/gitlab-basics/create-project.md | 4 | ||||
-rw-r--r-- | spec/features/projects_spec.rb | 18 | ||||
-rw-r--r-- | spec/helpers/projects_helper_spec.rb | 16 |
11 files changed, 118 insertions, 10 deletions
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 7d2cf4b634f..017f3b986fd 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -418,6 +418,16 @@ export const convertObjectPropsToCamelCase = (obj = {}) => { export const imagePath = imgUrl => `${gon.asset_host || ''}${gon.relative_url_root || ''}/assets/${imgUrl}`; +export const addSelectOnFocusBehaviour = (selector = '.js-select-on-focus') => { + // Click a .js-select-on-focus field, select the contents + // Prevent a mouseup event from deselecting the input + $(selector).on('focusin', function selectOnFocusCallback() { + $(this).select().one('mouseup', (e) => { + e.preventDefault(); + }); + }); +}; + window.gl = window.gl || {}; window.gl.utils = { ...(window.gl.utils || {}), diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index dc9e5bb03f4..659dc9eaa1f 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -10,7 +10,7 @@ window.jQuery = jQuery; window.$ = jQuery; // lib/utils -import { handleLocationHash } from './lib/utils/common_utils'; +import { handleLocationHash, addSelectOnFocusBehaviour } from './lib/utils/common_utils'; import { localTimeAgo } from './lib/utils/datetime_utility'; import { getLocationHash, visitUrl } from './lib/utils/url_utility'; @@ -104,13 +104,7 @@ document.addEventListener('DOMContentLoaded', () => { return true; }); - // Click a .js-select-on-focus field, select the contents - // Prevent a mouseup event from deselecting the input - $('.js-select-on-focus').on('focusin', function selectOnFocusCallback() { - $(this).select().one('mouseup', (e) => { - e.preventDefault(); - }); - }); + addSelectOnFocusBehaviour('.js-select-on-focus'); $('.remove-row').on('ajax:success', function removeRowAjaxSuccessCallback() { $(this).tooltip('destroy') diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js index f5133111d04..8da37d14f0b 100644 --- a/app/assets/javascripts/projects/project_new.js +++ b/app/assets/javascripts/projects/project_new.js @@ -1,3 +1,5 @@ +import { addSelectOnFocusBehaviour } from '../lib/utils/common_utils'; + let hasUserDefinedProjectPath = false; const deriveProjectPathFromUrl = ($projectImportUrl) => { @@ -36,6 +38,7 @@ const bindEvents = () => { const $changeTemplateBtn = $('.change-template'); const $selectedIcon = $('.selected-icon svg'); const $templateProjectNameInput = $('#template-project-name #project_path'); + const $pushNewProjectTipTrigger = $('.push-new-project-tip'); if ($newProjectForm.length !== 1) { return; @@ -55,6 +58,34 @@ const bindEvents = () => { $('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`); }); + if ($pushNewProjectTipTrigger) { + $pushNewProjectTipTrigger + .removeAttr('rel') + .removeAttr('target') + .on('click', (e) => { e.preventDefault(); }) + .popover({ + title: $pushNewProjectTipTrigger.data('title'), + placement: 'auto bottom', + html: 'true', + content: $('.push-new-project-tip-template').html(), + }) + .on('shown.bs.popover', () => { + $(document).on('click.popover touchstart.popover', (event) => { + if ($(event.target).closest('.popover').length === 0) { + $pushNewProjectTipTrigger.trigger('click'); + } + }); + + const target = $(`#${$pushNewProjectTipTrigger.attr('aria-describedby')}`).find('.js-select-on-focus'); + addSelectOnFocusBehaviour(target); + + target.focus(); + }) + .on('hide.bs.popover', () => { + $(document).off('click.popover touchstart.popover'); + }); + } + function chooseTemplate() { $('.template-option').hide(); $projectFieldsForm.addClass('selected'); diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss index fef5a1f51fa..294c59f037f 100644 --- a/app/assets/stylesheets/framework/typography.scss +++ b/app/assets/stylesheets/framework/typography.scss @@ -333,6 +333,10 @@ a > code { font-family: $monospace_font; } +.weight-normal { + font-weight: $gl-font-weight-normal; +} + .commit-sha, .ref-name { @extend .monospace; diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss index 93d232149c1..85de0d8e70f 100644 --- a/app/assets/stylesheets/pages/projects.scss +++ b/app/assets/stylesheets/pages/projects.scss @@ -896,6 +896,12 @@ pre.light-well { } } +.project-tip-command { + > .input-group-btn:first-child { + width: auto; + } +} + .protected-branches-list, .protected-tags-list { margin-bottom: 30px; diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 42b5eb11ef5..6ea83d63039 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -260,6 +260,17 @@ module ProjectsHelper !!(params[:personal] || params[:name] || any_projects?(projects)) end + def push_to_create_project_command(user = current_user) + repository_url = + if Gitlab::CurrentSettings.current_application_settings.enabled_git_access_protocol == 'http' + user_url(user) + else + Gitlab.config.gitlab_shell.ssh_path_prefix + user.username + end + + "git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)" + end + private def repo_children_classes(field) diff --git a/app/views/projects/_new_project_push_tip.html.haml b/app/views/projects/_new_project_push_tip.html.haml new file mode 100644 index 00000000000..9bc69211d12 --- /dev/null +++ b/app/views/projects/_new_project_push_tip.html.haml @@ -0,0 +1,11 @@ +.push-to-create-popover + %p + = label_tag(:push_to_create_tip, _("Private projects can be created in your personal namespace with:"), class: "weight-normal") + + %p.input-group.project-tip-command + %span.input-group-btn + = text_field_tag :push_to_create_tip, push_to_create_project_command, class: "js-select-on-focus form-control monospace", readonly: true, aria: { label: _("Push project from command line") } + %span.input-group-btn + = clipboard_button(text: push_to_create_project_command, title: _("Copy command to clipboard"), placement: "right") + %p + = link_to("What does this command do?", help_page_path("gitlab-basics/create-project", anchor: "push-to-create-a-new-project"), target: "_blank") diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 61ae0ebbce6..a004f2c1aa0 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -18,6 +18,13 @@ All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings. .md = brand_new_project_guidelines + %p + %strong= _("Tip:") + = _("You can also create a project from the command line.") + %a.push-new-project-tip{ data: { title: _("Push to create a project") }, href: help_page_path('gitlab-basics/create-project', anchor: 'push-to-create-a-new-project'), target: "_blank", rel: "noopener noreferrer" } + = _("Show command") + %template.push-new-project-tip-template= render partial: "new_project_push_tip" + .col-lg-9.js-toggle-container %ul.nav-links.gitlab-tabs{ role: 'tablist' } %li.active{ role: 'presentation' } diff --git a/doc/gitlab-basics/create-project.md b/doc/gitlab-basics/create-project.md index e745b51f668..10e8059756d 100644 --- a/doc/gitlab-basics/create-project.md +++ b/doc/gitlab-basics/create-project.md @@ -47,10 +47,10 @@ This can be done by using either SSH or HTTP: ``` ## Git push using SSH -git push git@gitlab.example.com:namespace/nonexistent-project.git +git push --set-upstream git@gitlab.example.com:namespace/nonexistent-project.git master ## Git push using HTTP -git push https://gitlab.example.com/namespace/nonexistent-project.git +git push --set-upstream https://gitlab.example.com/namespace/nonexistent-project.git master ``` Once the push finishes successfully, a remote message will indicate diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index b66a7dea598..645d12da09f 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -25,6 +25,24 @@ feature 'Project' do end end + describe 'shows tip about push to create git command' do + let(:user) { create(:user) } + + before do + sign_in user + visit new_project_path + end + + it 'shows the command in a popover', :js do + page.within '.profile-settings-sidebar' do + click_link 'Show command' + end + + expect(page).to have_css('.popover .push-to-create-popover #push_to_create_tip') + expect(page).to have_content 'Private projects can be created in your personal namespace with:' + end + end + describe 'description' do let(:project) { create(:project, :repository) } let(:path) { project_path(project) } diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index a160cc9d5ec..b643a3590c8 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -436,6 +436,22 @@ describe ProjectsHelper do end end + describe('#push_to_create_project_command') do + let(:user) { create(:user, username: 'john') } + + it 'returns the command to push to create project over HTTP' do + allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'http' } + + expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream http://test.host/john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)') + end + + it 'returns the command to push to create project over SSH' do + allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'ssh' } + + expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream git@localhost:john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)') + end + end + describe '#any_projects?' do let!(:project) { create(:project) } |