Commit 6015b521 authored by Phil Hughes's avatar Phil Hughes

Merge branch '60540-merge-request-popover-is-not-working-on-the-to-do-page' into 'master'

Resolve "Merge Request Popover is not working on the To Do page"

Closes #60540

See merge request gitlab-org/gitlab-ce!27382
parents 27a96407 699957ef
...@@ -22,13 +22,10 @@ const handleUserPopoverMouseOut = ({ target }) => { ...@@ -22,13 +22,10 @@ const handleUserPopoverMouseOut = ({ target }) => {
* Adds a MergeRequestPopover component to the body, hands over as much data as the target element has in data attributes. * Adds a MergeRequestPopover component to the body, hands over as much data as the target element has in data attributes.
* loads based on data-project-path and data-iid more data about an MR from the API and sets it on the popover * loads based on data-project-path and data-iid more data about an MR from the API and sets it on the popover
*/ */
const handleMRPopoverMount = apolloProvider => ({ target }) => { const handleMRPopoverMount = ({ apolloProvider, projectPath, mrTitle, iid }) => ({ target }) => {
// Add listener to actually remove it again // Add listener to actually remove it again
target.addEventListener('mouseleave', handleUserPopoverMouseOut); target.addEventListener('mouseleave', handleUserPopoverMouseOut);
const { projectPath, mrTitle, iid } = target.dataset;
const mergeRequest = {};
renderFn = setTimeout(() => { renderFn = setTimeout(() => {
const MRPopoverComponent = Vue.extend(MRPopover); const MRPopoverComponent = Vue.extend(MRPopover);
renderedPopover = new MRPopoverComponent({ renderedPopover = new MRPopoverComponent({
...@@ -36,7 +33,6 @@ const handleMRPopoverMount = apolloProvider => ({ target }) => { ...@@ -36,7 +33,6 @@ const handleMRPopoverMount = apolloProvider => ({ target }) => {
target, target,
projectPath, projectPath,
mergeRequestIID: iid, mergeRequestIID: iid,
mergeRequest,
mergeRequestTitle: mrTitle, mergeRequestTitle: mrTitle,
}, },
apolloProvider, apolloProvider,
...@@ -57,8 +53,13 @@ export default elements => { ...@@ -57,8 +53,13 @@ export default elements => {
const listenerAddedAttr = 'data-mr-listener-added'; const listenerAddedAttr = 'data-mr-listener-added';
mrLinks.forEach(el => { mrLinks.forEach(el => {
if (!el.getAttribute(listenerAddedAttr)) { const { projectPath, mrTitle, iid } = el.dataset;
el.addEventListener('mouseenter', handleMRPopoverMount(apolloProvider));
if (!el.getAttribute(listenerAddedAttr) && projectPath && mrTitle && iid) {
el.addEventListener(
'mouseenter',
handleMRPopoverMount({ apolloProvider, projectPath, mrTitle, iid }),
);
el.setAttribute(listenerAddedAttr, true); el.setAttribute(listenerAddedAttr, true);
} }
}); });
......
...@@ -83,7 +83,8 @@ module MarkupHelper ...@@ -83,7 +83,8 @@ module MarkupHelper
text = sanitize( text = sanitize(
text, text,
tags: tags, tags: tags,
attributes: Rails::Html::WhiteListSanitizer.allowed_attributes + ['style', 'data-src', 'data-name', 'data-unicode-version'] attributes: Rails::Html::WhiteListSanitizer.allowed_attributes +
%w(style data-src data-name data-unicode-version data-iid data-project-path data-mr-title)
) )
# since <img> tags are stripped, this can leave empty <a> tags hanging around # since <img> tags are stripped, this can leave empty <a> tags hanging around
......
---
title: Fix MR popover on ToDos page
merge_request: 27382
author:
type: fixed
...@@ -17,6 +17,26 @@ describe 'Dashboard Todos' do ...@@ -17,6 +17,26 @@ describe 'Dashboard Todos' do
end end
end end
context 'when the todo references a merge request' do
let(:referenced_mr) { create(:merge_request, source_project: project) }
let(:note) { create(:note, project: project, note: "Check out #{referenced_mr.to_reference}") }
let!(:todo) { create(:todo, :mentioned, user: user, project: project, author: author, note: note) }
before do
sign_in(user)
visit dashboard_todos_path
end
it 'renders the mr link with the extra attributes' do
link = page.find_link(referenced_mr.to_reference)
expect(link).not_to be_nil
expect(link['data-iid']).to eq(referenced_mr.iid.to_s)
expect(link['data-project-path']).to eq(referenced_mr.project.full_path)
expect(link['data-mr-title']).to eq(referenced_mr.title)
end
end
context 'User has a todo', :js do context 'User has a todo', :js do
before do before do
create(:todo, :mentioned, user: user, project: project, target: issue, author: author) create(:todo, :mentioned, user: user, project: project, target: issue, author: author)
......
...@@ -7,18 +7,28 @@ createDefaultClient.default = jest.fn(); ...@@ -7,18 +7,28 @@ createDefaultClient.default = jest.fn();
describe('initMRPopovers', () => { describe('initMRPopovers', () => {
let mr1; let mr1;
let mr2; let mr2;
let mr3;
beforeEach(() => { beforeEach(() => {
setHTMLFixture(` setHTMLFixture(`
<div id="one" class="gfm-merge_request">MR1</div> <div id="one" class="gfm-merge_request" data-mr-title="title" data-iid="1" data-project-path="group/project">
<div id="two" class="gfm-merge_request">MR2</div> MR1
</div>
<div id="two" class="gfm-merge_request" data-mr-title="title" data-iid="1" data-project-path="group/project">
MR2
</div>
<div id="three" class="gfm-merge_request">
MR3
</div>
`); `);
mr1 = document.querySelector('#one'); mr1 = document.querySelector('#one');
mr2 = document.querySelector('#two'); mr2 = document.querySelector('#two');
mr3 = document.querySelector('#three');
mr1.addEventListener = jest.fn(); mr1.addEventListener = jest.fn();
mr2.addEventListener = jest.fn(); mr2.addEventListener = jest.fn();
mr3.addEventListener = jest.fn();
}); });
it('does not add the same event listener twice', () => { it('does not add the same event listener twice', () => {
...@@ -27,4 +37,10 @@ describe('initMRPopovers', () => { ...@@ -27,4 +37,10 @@ describe('initMRPopovers', () => {
expect(mr1.addEventListener).toHaveBeenCalledTimes(1); expect(mr1.addEventListener).toHaveBeenCalledTimes(1);
expect(mr2.addEventListener).toHaveBeenCalledTimes(1); expect(mr2.addEventListener).toHaveBeenCalledTimes(1);
}); });
it('does not add listener if it does not have the necessary data attributes', () => {
initMRPopovers([mr1, mr2, mr3]);
expect(mr3.addEventListener).not.toHaveBeenCalled();
});
}); });
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