Added more actions and report as abuse to all notes
This commit is contained in:
parent
8bd232d43b
commit
32cac59727
21 changed files with 314 additions and 22 deletions
|
@ -201,6 +201,11 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
&.dropdown-open-left {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
&.is-loading {
|
||||
.dropdown-content {
|
||||
display: none;
|
||||
|
|
|
@ -38,9 +38,12 @@ ul.notes {
|
|||
}
|
||||
|
||||
.discussion {
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
.diff-content {
|
||||
overflow: visible;
|
||||
}
|
||||
}
|
||||
|
||||
> li {
|
||||
|
@ -443,6 +446,53 @@ ul.notes {
|
|||
.note-action-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.more-actions-toggle {
|
||||
margin-left: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.more-actions {
|
||||
display: inline;
|
||||
|
||||
.tooltip {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.more-actions-toggle {
|
||||
padding: 0;
|
||||
outline: none;
|
||||
|
||||
&:hover .icon,
|
||||
&:focus .icon {
|
||||
color: $blue-600;
|
||||
}
|
||||
|
||||
.icon {
|
||||
padding: 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.more-actions-dropdown {
|
||||
width: 180px;
|
||||
min-width: 180px;
|
||||
margin-top: $gl-btn-padding;
|
||||
|
||||
li > a,
|
||||
li > .btn {
|
||||
color: $gl-text-color;
|
||||
padding: $gl-btn-padding;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $gl-text-color;
|
||||
background-color: $blue-25;
|
||||
border-radius: $border-radius-default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.discussion-actions {
|
||||
|
|
|
@ -90,14 +90,18 @@ module NotesHelper
|
|||
end
|
||||
end
|
||||
|
||||
def note_url(note)
|
||||
def note_url(note, project = @project)
|
||||
if note.noteable.is_a?(PersonalSnippet)
|
||||
snippet_note_path(note.noteable, note)
|
||||
else
|
||||
namespace_project_note_path(@project.namespace, @project, note)
|
||||
namespace_project_note_path(project.namespace, project, note)
|
||||
end
|
||||
end
|
||||
|
||||
def noteable_note_url(note)
|
||||
Gitlab::UrlBuilder.build(note)
|
||||
end
|
||||
|
||||
def form_resources
|
||||
if @snippet.is_a?(PersonalSnippet)
|
||||
[@note]
|
||||
|
|
|
@ -37,8 +37,4 @@
|
|||
%span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')
|
||||
%span{ class: 'link-highlight award-control-icon-super-positive' }= custom_icon('emoji_smile')
|
||||
|
||||
- if note_editable
|
||||
= link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit has-tooltip' do
|
||||
= icon('pencil', class: 'link-highlight')
|
||||
= link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button js-note-delete danger has-tooltip' do
|
||||
= icon('trash-o', class: 'danger-highlight')
|
||||
= render 'projects/notes/more_actions_dropdown', note: note, note_editable: note_editable
|
||||
|
|
14
app/views/projects/notes/_more_actions_dropdown.html.haml
Normal file
14
app/views/projects/notes/_more_actions_dropdown.html.haml
Normal file
|
@ -0,0 +1,14 @@
|
|||
.dropdown.more-actions
|
||||
= button_tag title: 'More actions', class: 'note-action-button more-actions-toggle has-tooltip btn btn-transparent', data: { toggle: 'dropdown', container: 'body' } do
|
||||
= icon('ellipsis-v', class: 'icon')
|
||||
%ul.dropdown-menu.more-actions-dropdown.dropdown-open-left
|
||||
%li
|
||||
= button_tag 'Edit comment', class: 'js-note-edit btn btn-transparent'
|
||||
%li.divider
|
||||
%li
|
||||
= link_to new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) do
|
||||
Report as abuse
|
||||
- if note_editable
|
||||
%li
|
||||
= link_to note_url(note), method: :delete, data: { confirm: 'Are you sure you want to delete this comment?' }, remote: true, class: 'js-note-delete' do
|
||||
%span.text-danger Delete comment
|
|
@ -6,8 +6,5 @@
|
|||
%span{ class: 'link-highlight award-control-icon-neutral' }= custom_icon('emoji_slightly_smiling_face')
|
||||
%span{ class: 'link-highlight award-control-icon-positive' }= custom_icon('emoji_smiley')
|
||||
%span{ class: 'link-highlight award-control-icon-super-positive' }= custom_icon('emoji_smile')
|
||||
- if note_editable
|
||||
= link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit has-tooltip' do
|
||||
= icon('pencil', class: 'link-highlight')
|
||||
= link_to snippet_note_path(note.noteable, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button js-note-delete danger has-tooltip' do
|
||||
= icon('trash-o', class: 'danger-highlight')
|
||||
|
||||
= render 'projects/notes/more_actions_dropdown', note: note, note_editable: note_editable
|
||||
|
|
|
@ -297,6 +297,9 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
|||
|
||||
step 'I change the comment "Line is wrong" to "Typo, please fix" on diff' do
|
||||
page.within('.diff-file:nth-of-type(5) .note') do
|
||||
find('.more-actions').click
|
||||
find('.more-actions .dropdown-menu li', match: :first)
|
||||
|
||||
find('.js-note-edit').click
|
||||
|
||||
page.within('.current-note-edit-form', visible: true) do
|
||||
|
@ -322,6 +325,9 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
|
|||
|
||||
step 'I delete the comment "Line is wrong" on diff' do
|
||||
page.within('.diff-file:nth-of-type(5) .note') do
|
||||
find('.more-actions').click
|
||||
find('.more-actions .dropdown-menu li', match: :first)
|
||||
|
||||
find('.js-note-delete').click
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,12 @@ module SharedNote
|
|||
|
||||
step 'I delete a comment' do
|
||||
page.within('.main-notes-list') do
|
||||
find('.note').hover
|
||||
note = find('.note')
|
||||
note.hover
|
||||
|
||||
note.find('.more-actions').click
|
||||
note.find('.more-actions .dropdown-menu li', match: :first)
|
||||
|
||||
find(".js-note-delete").click
|
||||
end
|
||||
end
|
||||
|
@ -139,8 +144,13 @@ module SharedNote
|
|||
|
||||
step 'I edit the last comment with a +1' do
|
||||
page.within(".main-notes-list") do
|
||||
find(".note").hover
|
||||
find('.js-note-edit').click
|
||||
note = find('.note')
|
||||
note.hover
|
||||
|
||||
note.find('.more-actions').click
|
||||
note.find('.more-actions .dropdown-menu li', match: :first)
|
||||
|
||||
note.find('.js-note-edit').click
|
||||
end
|
||||
|
||||
page.within(".current-note-edit-form") do
|
||||
|
|
|
@ -61,7 +61,12 @@ module Gitlab
|
|||
|
||||
elsif object.for_snippet?
|
||||
snippet = Snippet.find(object.noteable_id)
|
||||
project_snippet_url(snippet, anchor: dom_id(object))
|
||||
|
||||
if snippet.is_a?(PersonalSnippet)
|
||||
snippet_url(snippet, anchor: dom_id(object))
|
||||
else
|
||||
project_snippet_url(snippet, anchor: dom_id(object))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Issue notes polling', :feature, :js do
|
||||
include NoteInteractionHelpers
|
||||
|
||||
let(:project) { create(:empty_project, :public) }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
|
||||
|
@ -48,7 +50,7 @@ feature 'Issue notes polling', :feature, :js do
|
|||
end
|
||||
|
||||
it 'when editing but have not changed anything, and an update comes in, show the updated content in the textarea' do
|
||||
find("#note_#{existing_note.id} .js-note-edit").click
|
||||
click_edit_action(existing_note)
|
||||
|
||||
expect(page).to have_field("note[note]", with: note_text)
|
||||
|
||||
|
@ -58,19 +60,18 @@ feature 'Issue notes polling', :feature, :js do
|
|||
end
|
||||
|
||||
it 'when editing but you changed some things, and an update comes in, show a warning' do
|
||||
find("#note_#{existing_note.id} .js-note-edit").click
|
||||
click_edit_action(existing_note)
|
||||
|
||||
expect(page).to have_field("note[note]", with: note_text)
|
||||
|
||||
find("#note_#{existing_note.id} .js-note-text").set('something random')
|
||||
|
||||
update_note(existing_note, updated_text)
|
||||
|
||||
expect(page).to have_selector(".alert")
|
||||
end
|
||||
|
||||
it 'when editing but you changed some things, an update comes in, and you press cancel, show the updated content' do
|
||||
find("#note_#{existing_note.id} .js-note-edit").click
|
||||
click_edit_action(existing_note)
|
||||
|
||||
expect(page).to have_field("note[note]", with: note_text)
|
||||
|
||||
|
@ -128,4 +129,12 @@ feature 'Issue notes polling', :feature, :js do
|
|||
note.update(note: new_text)
|
||||
page.execute_script('notes.refresh();')
|
||||
end
|
||||
|
||||
def click_edit_action(note)
|
||||
note_element = find("#note_#{note.id}")
|
||||
|
||||
open_more_actions_dropdown(note)
|
||||
|
||||
note_element.find('.js-note-edit').click
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Diff note avatars', feature: true, js: true do
|
||||
include NoteInteractionHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project, :public) }
|
||||
let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: "Bug NS-04") }
|
||||
|
@ -110,6 +112,8 @@ feature 'Diff note avatars', feature: true, js: true do
|
|||
end
|
||||
|
||||
it 'removes avatar when note is deleted' do
|
||||
open_more_actions_dropdown(note)
|
||||
|
||||
page.within find(".note-row-#{note.id}") do
|
||||
find('.js-note-delete').click
|
||||
end
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Merge requests > User posts notes', :js do
|
||||
include NoteInteractionHelpers
|
||||
|
||||
let(:project) { create(:project) }
|
||||
let(:merge_request) do
|
||||
create(:merge_request, source_project: project, target_project: project)
|
||||
|
@ -73,6 +75,8 @@ describe 'Merge requests > User posts notes', :js do
|
|||
describe 'editing the note' do
|
||||
before do
|
||||
find('.note').hover
|
||||
open_more_actions_dropdown(note)
|
||||
|
||||
find('.js-note-edit').click
|
||||
end
|
||||
|
||||
|
@ -100,6 +104,8 @@ describe 'Merge requests > User posts notes', :js do
|
|||
|
||||
wait_for_requests
|
||||
find('.note').hover
|
||||
open_more_actions_dropdown(note)
|
||||
|
||||
find('.js-note-edit').click
|
||||
|
||||
page.within('.current-note-edit-form') do
|
||||
|
@ -126,6 +132,8 @@ describe 'Merge requests > User posts notes', :js do
|
|||
describe 'deleting an attachment' do
|
||||
before do
|
||||
find('.note').hover
|
||||
open_more_actions_dropdown(note)
|
||||
|
||||
find('.js-note-edit').click
|
||||
end
|
||||
|
||||
|
|
33
spec/features/reportable_note/commit_spec.rb
Normal file
33
spec/features/reportable_note/commit_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Reportable note on commit', :feature, :js do
|
||||
include RepoHelpers
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
|
||||
before do
|
||||
project.add_master(user)
|
||||
login_as user
|
||||
end
|
||||
|
||||
context 'a normal note' do
|
||||
let!(:note) { create(:note_on_commit, commit_id: sample_commit.id, project: project) }
|
||||
|
||||
before do
|
||||
visit namespace_project_commit_path(project.namespace, project, sample_commit.id)
|
||||
end
|
||||
|
||||
it_behaves_like 'reportable note'
|
||||
end
|
||||
|
||||
context 'a diff note' do
|
||||
let!(:note) { create(:diff_note_on_commit, commit_id: sample_commit.id, project: project) }
|
||||
|
||||
before do
|
||||
visit namespace_project_commit_path(project.namespace, project, sample_commit.id)
|
||||
end
|
||||
|
||||
it_behaves_like 'reportable note'
|
||||
end
|
||||
end
|
17
spec/features/reportable_note/issue_spec.rb
Normal file
17
spec/features/reportable_note/issue_spec.rb
Normal file
|
@ -0,0 +1,17 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Reportable note on issue', :feature, :js do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:empty_project) }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
let!(:note) { create(:note_on_issue, noteable: issue, project: project) }
|
||||
|
||||
before do
|
||||
project.add_master(user)
|
||||
login_as user
|
||||
|
||||
visit namespace_project_issue_path(project.namespace, project, issue)
|
||||
end
|
||||
|
||||
it_behaves_like 'reportable note'
|
||||
end
|
26
spec/features/reportable_note/merge_request_spec.rb
Normal file
26
spec/features/reportable_note/merge_request_spec.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Reportable note on merge request', :feature, :js do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:project) }
|
||||
let(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
||||
before do
|
||||
project.add_master(user)
|
||||
login_as user
|
||||
|
||||
visit namespace_project_merge_request_path(project.namespace, project, merge_request)
|
||||
end
|
||||
|
||||
context 'a normal note' do
|
||||
let!(:note) { create(:note_on_merge_request, noteable: merge_request, project: project) }
|
||||
|
||||
it_behaves_like 'reportable note'
|
||||
end
|
||||
|
||||
context 'a diff note' do
|
||||
let!(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
|
||||
|
||||
it_behaves_like 'reportable note'
|
||||
end
|
||||
end
|
33
spec/features/reportable_note/snippets_spec.rb
Normal file
33
spec/features/reportable_note/snippets_spec.rb
Normal file
|
@ -0,0 +1,33 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Reportable note on snippets', :feature, :js do
|
||||
let(:user) { create(:user) }
|
||||
let(:project) { create(:empty_project) }
|
||||
|
||||
before do
|
||||
project.add_master(user)
|
||||
login_as user
|
||||
end
|
||||
|
||||
describe 'on project snippet' do
|
||||
let(:snippet) { create(:project_snippet, :public, project: project, author: user) }
|
||||
let!(:note) { create(:note_on_project_snippet, noteable: snippet, project: project) }
|
||||
|
||||
before do
|
||||
visit namespace_project_snippet_path(project.namespace, project, snippet)
|
||||
end
|
||||
|
||||
it_behaves_like 'reportable note'
|
||||
end
|
||||
|
||||
describe 'on personal snippet' do
|
||||
let(:snippet) { create(:personal_snippet, :public, author: user) }
|
||||
let!(:note) { create(:note_on_personal_snippet, noteable: snippet, author: user) }
|
||||
|
||||
before do
|
||||
visit snippet_path(snippet)
|
||||
end
|
||||
|
||||
it_behaves_like 'reportable note'
|
||||
end
|
||||
end
|
|
@ -1,6 +1,8 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Comments on personal snippets', :js, feature: true do
|
||||
include NoteInteractionHelpers
|
||||
|
||||
let!(:user) { create(:user) }
|
||||
let!(:snippet) { create(:personal_snippet, :public) }
|
||||
let!(:snippet_notes) do
|
||||
|
@ -22,6 +24,8 @@ describe 'Comments on personal snippets', :js, feature: true do
|
|||
it 'contains notes for a snippet with correct action icons' do
|
||||
expect(page).to have_selector('#notes-list li', count: 2)
|
||||
|
||||
open_more_actions_dropdown(snippet_notes[0])
|
||||
|
||||
# comment authored by current user
|
||||
page.within("#notes-list li#note_#{snippet_notes[0].id}") do
|
||||
expect(page).to have_content(snippet_notes[0].note)
|
||||
|
@ -29,6 +33,8 @@ describe 'Comments on personal snippets', :js, feature: true do
|
|||
expect(page).to have_selector('.note-emoji-button')
|
||||
end
|
||||
|
||||
open_more_actions_dropdown(snippet_notes[1])
|
||||
|
||||
page.within("#notes-list li#note_#{snippet_notes[1].id}") do
|
||||
expect(page).to have_content(snippet_notes[1].note)
|
||||
expect(page).not_to have_selector('.js-note-delete')
|
||||
|
@ -68,6 +74,8 @@ describe 'Comments on personal snippets', :js, feature: true do
|
|||
|
||||
context 'when editing a note' do
|
||||
it 'changes the text' do
|
||||
open_more_actions_dropdown(snippet_notes[0])
|
||||
|
||||
page.within("#notes-list li#note_#{snippet_notes[0].id}") do
|
||||
click_on 'Edit comment'
|
||||
end
|
||||
|
@ -89,8 +97,10 @@ describe 'Comments on personal snippets', :js, feature: true do
|
|||
|
||||
context 'when deleting a note' do
|
||||
it 'removes the note from the snippet detail page' do
|
||||
open_more_actions_dropdown(snippet_notes[0])
|
||||
|
||||
page.within("#notes-list li#note_#{snippet_notes[0].id}") do
|
||||
click_on 'Remove comment'
|
||||
click_on 'Delete comment'
|
||||
end
|
||||
|
||||
wait_for_requests
|
||||
|
|
|
@ -256,4 +256,14 @@ describe NotesHelper do
|
|||
expect(helper.form_resources).to eq([@project.namespace, @project, @note])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#noteable_note_url' do
|
||||
let(:project) { create(:empty_project) }
|
||||
let(:issue) { create(:issue, project: project) }
|
||||
let(:note) { create(:note_on_issue, noteable: issue, project: project) }
|
||||
|
||||
it 'returns the noteable url with an anchor to the note' do
|
||||
expect(noteable_note_url(note)).to match("/#{project.namespace.path}/#{project.path}/issues/#{issue.iid}##{dom_id(note)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -97,6 +97,17 @@ describe Gitlab::UrlBuilder, lib: true do
|
|||
end
|
||||
end
|
||||
|
||||
context 'on a PersonalSnippet' do
|
||||
it 'returns a proper URL' do
|
||||
personal_snippet = create(:personal_snippet)
|
||||
note = build_stubbed(:note_on_personal_snippet, noteable: personal_snippet)
|
||||
|
||||
url = described_class.build(note)
|
||||
|
||||
expect(url).to eq "#{Settings.gitlab['url']}/snippets/#{note.noteable_id}#note_#{note.id}"
|
||||
end
|
||||
end
|
||||
|
||||
context 'on another object' do
|
||||
it 'returns a proper URL' do
|
||||
project = build_stubbed(:empty_project)
|
||||
|
|
36
spec/support/features/reportable_note_shared_examples.rb
Normal file
36
spec/support/features/reportable_note_shared_examples.rb
Normal file
|
@ -0,0 +1,36 @@
|
|||
require 'spec_helper'
|
||||
|
||||
shared_examples 'reportable note' do
|
||||
include NotesHelper
|
||||
|
||||
let(:comment) { find("##{ActionView::RecordIdentifier.dom_id(note)}") }
|
||||
let(:more_actions_selector) { '.more-actions.dropdown' }
|
||||
let(:abuse_report_path) { new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) }
|
||||
|
||||
it 'has a `More actions` dropdown' do
|
||||
expect(comment).to have_selector(more_actions_selector)
|
||||
end
|
||||
|
||||
it 'dropdown has Edit, Report and Delete links' do
|
||||
dropdown = comment.find(more_actions_selector)
|
||||
|
||||
dropdown.click
|
||||
dropdown.find('.dropdown-menu li', match: :first)
|
||||
|
||||
expect(dropdown).to have_button('Edit comment')
|
||||
expect(dropdown).to have_link('Report as abuse', href: abuse_report_path)
|
||||
expect(dropdown).to have_link('Delete comment', href: note_url(note, project))
|
||||
end
|
||||
|
||||
it 'Report button links to a report page' do
|
||||
dropdown = comment.find(more_actions_selector)
|
||||
|
||||
dropdown.click
|
||||
dropdown.find('.dropdown-menu li', match: :first)
|
||||
|
||||
dropdown.click_link('Report as abuse')
|
||||
|
||||
expect(find('#user_name')['value']).to match(note.author.username)
|
||||
expect(find('#abuse_report_message')['value']).to match(noteable_note_url(note))
|
||||
end
|
||||
end
|
8
spec/support/helpers/note_interaction_helpers.rb
Normal file
8
spec/support/helpers/note_interaction_helpers.rb
Normal file
|
@ -0,0 +1,8 @@
|
|||
module NoteInteractionHelpers
|
||||
def open_more_actions_dropdown(note)
|
||||
note_element = find("#note_#{note.id}")
|
||||
|
||||
note_element.find('.more-actions').click
|
||||
note_element.find('.more-actions .dropdown-menu li', match: :first)
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue