Commit c4527291 authored by Douwe Maan's avatar Douwe Maan

Merge branch 'ee-31276-fix-diffs-with-edit-forking-needs' into 'master'

Fix diffs with edit-forking needs -- EE merge edition

Closes gitlab-ce#31276 and gitlab-ce#30637

See merge request !1705
parents 9cb1a114 e6e171fd
// ECMAScript polyfills // ECMAScript polyfills
import 'core-js/fn/array/find'; import 'core-js/fn/array/find';
import 'core-js/fn/array/from'; import 'core-js/fn/array/from';
import 'core-js/fn/array/includes';
import 'core-js/fn/object/assign'; import 'core-js/fn/object/assign';
import 'core-js/fn/promise'; import 'core-js/fn/promise';
import 'core-js/fn/string/code-point-at'; import 'core-js/fn/string/code-point-at';
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import './breakpoints'; import './breakpoints';
import './flash'; import './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
/* eslint-disable max-len */ /* eslint-disable max-len */
// MergeRequestTabs // MergeRequestTabs
...@@ -266,6 +267,17 @@ import './flash'; ...@@ -266,6 +267,17 @@ import './flash';
new gl.Diff(); new gl.Diff();
this.scrollToElement('#diffs'); this.scrollToElement('#diffs');
$('.diff-file').each((i, el) => {
new BlobForkSuggestion({
openButtons: $(el).find('.js-edit-blob-link-fork-toggler'),
forkButtons: $(el).find('.js-fork-suggestion-button'),
cancelButtons: $(el).find('.js-cancel-fork-suggestion-button'),
suggestionSections: $(el).find('.js-file-fork-suggestion-section'),
actionTextPieces: $(el).find('.js-file-fork-suggestion-section-action'),
})
.init();
});
}, },
}); });
} }
......
...@@ -14,15 +14,6 @@ module BlobHelper ...@@ -14,15 +14,6 @@ module BlobHelper
options[:link_opts]) options[:link_opts])
end end
def fork_path(project = @project, ref = @ref, path = @path, options = {})
continue_params = {
to: edit_path,
notice: edit_in_new_fork_notice,
notice_now: edit_in_new_fork_notice_now
}
namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
end
def edit_blob_link(project = @project, ref = @ref, path = @path, options = {}) def edit_blob_link(project = @project, ref = @ref, path = @path, options = {})
blob = options.delete(:blob) blob = options.delete(:blob)
blob ||= project.repository.blob_at(ref, path) rescue nil blob ||= project.repository.blob_at(ref, path) rescue nil
...@@ -37,7 +28,16 @@ module BlobHelper ...@@ -37,7 +28,16 @@ module BlobHelper
elsif !current_user || (current_user && can_modify_blob?(blob, project, ref)) elsif !current_user || (current_user && can_modify_blob?(blob, project, ref))
link_to 'Edit', edit_path(project, ref, path, options), class: "#{common_classes} btn-sm" link_to 'Edit', edit_path(project, ref, path, options), class: "#{common_classes} btn-sm"
elsif current_user && can?(current_user, :fork_project, project) elsif current_user && can?(current_user, :fork_project, project)
button_tag 'Edit', class: "#{common_classes} js-edit-blob-link-fork-toggler" continue_params = {
to: edit_path(project, ref, path, options),
notice: edit_in_new_fork_notice,
notice_now: edit_in_new_fork_notice_now
}
fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
button_tag 'Edit',
class: "#{common_classes} js-edit-blob-link-fork-toggler",
data: { action: 'edit', fork_path: fork_path }
end end
end end
...@@ -48,21 +48,25 @@ module BlobHelper ...@@ -48,21 +48,25 @@ module BlobHelper
return unless blob return unless blob
common_classes = "btn btn-#{btn_class}"
if !on_top_of_branch?(project, ref) if !on_top_of_branch?(project, ref)
button_tag label, class: "btn btn-#{btn_class} disabled has-tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' } button_tag label, class: "#{common_classes} disabled has-tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' }
elsif blob.lfs_pointer? elsif blob.lfs_pointer?
button_tag label, class: "btn btn-#{btn_class} disabled has-tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' } button_tag label, class: "#{common_classes} disabled has-tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' }
elsif can_modify_blob?(blob, project, ref) elsif can_modify_blob?(blob, project, ref)
button_tag label, class: "btn btn-#{btn_class}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal' button_tag label, class: "#{common_classes}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal'
elsif can?(current_user, :fork_project, project) elsif can?(current_user, :fork_project, project)
continue_params = { continue_params = {
to: request.fullpath, to: request.fullpath,
notice: edit_in_new_fork_notice + " Try to #{action} this file again.", notice: edit_in_new_fork_notice + " Try to #{action} this file again.",
notice_now: edit_in_new_fork_notice_now notice_now: edit_in_new_fork_notice_now
} }
fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params) fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
link_to label, fork_path, class: "btn btn-#{btn_class}", method: :post button_tag label,
class: "#{common_classes} js-edit-blob-link-fork-toggler",
data: { action: action, fork_path: fork_path }
end end
end end
......
- if current_user
.js-file-fork-suggestion-section.file-fork-suggestion.hidden
%span.file-fork-suggestion-note
You're not allowed to
%span.js-file-fork-suggestion-section-action
edit
files in this project directly. Please fork this project,
make your changes there, and submit a merge request.
= link_to 'Fork', nil, method: :post, class: 'js-fork-suggestion-button btn btn-grouped btn-inverted btn-new'
%button.js-cancel-fork-suggestion-button.btn.btn-grouped{ type: 'button' }
Cancel
...@@ -40,13 +40,8 @@ ...@@ -40,13 +40,8 @@
- if current_user - if current_user
= replace_blob_link = replace_blob_link
= delete_blob_link = delete_blob_link
- if current_user
.js-file-fork-suggestion-section.file-fork-suggestion.hidden = render 'projects/fork_suggestion'
%span.file-fork-suggestion-note
You don't have permission to edit this file. Try forking this project to edit the file.
= link_to 'Fork', fork_path, method: :post, class: 'btn btn-grouped btn-inverted btn-new'
%button.js-cancel-fork-suggestion.btn.btn-grouped{ type: 'button' }
Cancel
- if license_allows_file_locks? - if license_allows_file_locks?
:javascript :javascript
......
...@@ -18,4 +18,6 @@ ...@@ -18,4 +18,6 @@
= view_file_button(diff_commit.id, diff_file.new_path, project) = view_file_button(diff_commit.id, diff_file.new_path, project)
= view_on_environment_button(diff_commit.id, diff_file.new_path, environment) if environment = view_on_environment_button(diff_commit.id, diff_file.new_path, environment) if environment
= render 'projects/fork_suggestion'
= render 'projects/diffs/content', diff_file: diff_file, diff_commit: diff_commit, blob: blob, project: project = render 'projects/diffs/content', diff_file: diff_file, diff_commit: diff_commit, blob: blob, project: project
...@@ -117,6 +117,8 @@ Feature: Project Source Browse Files ...@@ -117,6 +117,8 @@ Feature: Project Source Browse Files
And I click on ".gitignore" file in repo And I click on ".gitignore" file in repo
And I see the ".gitignore" And I see the ".gitignore"
And I click on "Replace" And I click on "Replace"
Then I should see a Fork/Cancel combo
And I click button "Fork"
Then I should see a notice about a new fork having been created Then I should see a notice about a new fork having been created
When I click on "Replace" When I click on "Replace"
And I replace it with a text file And I replace it with a text file
...@@ -265,6 +267,8 @@ Feature: Project Source Browse Files ...@@ -265,6 +267,8 @@ Feature: Project Source Browse Files
And I click on ".gitignore" file in repo And I click on ".gitignore" file in repo
And I see the ".gitignore" And I see the ".gitignore"
And I click on "Delete" And I click on "Delete"
Then I should see a Fork/Cancel combo
And I click button "Fork"
Then I should see a notice about a new fork having been created Then I should see a notice about a new fork having been created
When I click on "Delete" When I click on "Delete"
And I fill the commit message And I fill the commit message
......
...@@ -377,7 +377,6 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps ...@@ -377,7 +377,6 @@ class Spinach::Features::ProjectSourceBrowseFiles < Spinach::FeatureSteps
step 'I should see a Fork/Cancel combo' do step 'I should see a Fork/Cancel combo' do
expect(page).to have_link 'Fork' expect(page).to have_link 'Fork'
expect(page).to have_button 'Cancel' expect(page).to have_button 'Cancel'
expect(page).to have_content 'You don\'t have permission to edit this file. Try forking this project to edit the file.'
end end
step 'I should see a notice about a new fork having been created' do step 'I should see a notice about a new fork having been created' do
......
require 'spec_helper' require 'spec_helper'
feature 'Diffs URL', js: true, feature: true do feature 'Diffs URL', js: true, feature: true do
before do include ApplicationHelper
login_as :admin
@merge_request = create(:merge_request) let(:author_user) { create(:user) }
@project = @merge_request.source_project let(:user) { create(:user) }
end let(:project) { create(:project, :public) }
let(:forked_project) { Projects::ForkService.new(project, author_user).execute }
let(:merge_request) { create(:merge_request_with_diffs, source_project: forked_project, target_project: project, author: author_user) }
context 'when visit with */* as accept header' do context 'when visit with */* as accept header' do
before(:each) do before(:each) do
...@@ -13,9 +15,9 @@ feature 'Diffs URL', js: true, feature: true do ...@@ -13,9 +15,9 @@ feature 'Diffs URL', js: true, feature: true do
end end
it 'renders the notes' do it 'renders the notes' do
create :note_on_merge_request, project: @project, noteable: @merge_request, note: 'Rebasing with master' create :note_on_merge_request, project: project, noteable: merge_request, note: 'Rebasing with master'
visit diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
# Load notes and diff through AJAX # Load notes and diff through AJAX
expect(page).to have_css('.note-text', visible: false, text: 'Rebasing with master') expect(page).to have_css('.note-text', visible: false, text: 'Rebasing with master')
...@@ -28,11 +30,38 @@ feature 'Diffs URL', js: true, feature: true do ...@@ -28,11 +30,38 @@ feature 'Diffs URL', js: true, feature: true do
allow_any_instance_of(MergeRequestDiff).to receive(:overflow?).and_return(true) allow_any_instance_of(MergeRequestDiff).to receive(:overflow?).and_return(true)
allow(Commit).to receive(:max_diff_options).and_return(max_files: 20, max_lines: 20) allow(Commit).to receive(:max_diff_options).and_return(max_files: 20, max_lines: 20)
visit diffs_namespace_project_merge_request_path(@project.namespace, @project, @merge_request) visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
page.within('.alert') do page.within('.alert') do
expect(page).to have_text("Too many changes to show. Plain diff Email patch To preserve expect(page).to have_text("Too many changes to show. Plain diff Email patch To preserve
performance only 3 of 3+ files are displayed.") performance only 3 of 3 files are displayed.")
end
end
end
describe 'when editing file' do
let(:changelog_id) { hexdigest("CHANGELOG") }
context 'as author' do
it 'shows direct edit link' do
login_as(author_user)
visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
expect(page).to have_selector("[id=\"#{changelog_id}\"] a.js-edit-blob")
end
end
context 'as user who needs to fork' do
it 'shows fork/cancel confirmation' do
login_as(user)
visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
# Throws `Capybara::Poltergeist::InvalidSelector` if we try to use `#hash` syntax
find("[id=\"#{changelog_id}\"] .js-edit-blob").click
expect(page).to have_selector('.js-fork-suggestion-button', count: 1)
expect(page).to have_selector('.js-cancel-fork-suggestion-button', count: 1)
end end
end end
end end
......
...@@ -26,6 +26,7 @@ describe('BlobForkSuggestion', () => { ...@@ -26,6 +26,7 @@ describe('BlobForkSuggestion', () => {
it('showSuggestionSection', () => { it('showSuggestionSection', () => {
blobForkSuggestion.showSuggestionSection('/foo', 'foo'); blobForkSuggestion.showSuggestionSection('/foo', 'foo');
expect(suggestionSection.classList.contains('hidden')).toEqual(false); expect(suggestionSection.classList.contains('hidden')).toEqual(false);
expect(forkButton.getAttribute('href')).toEqual('/foo'); expect(forkButton.getAttribute('href')).toEqual('/foo');
expect(actionTextPiece.textContent).toEqual('foo'); expect(actionTextPiece.textContent).toEqual('foo');
...@@ -33,6 +34,7 @@ describe('BlobForkSuggestion', () => { ...@@ -33,6 +34,7 @@ describe('BlobForkSuggestion', () => {
it('hideSuggestionSection', () => { it('hideSuggestionSection', () => {
blobForkSuggestion.hideSuggestionSection(); blobForkSuggestion.hideSuggestionSection();
expect(suggestionSection.classList.contains('hidden')).toEqual(true); expect(suggestionSection.classList.contains('hidden')).toEqual(true);
}); });
}); });
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