Commit dfc2d7d8 authored by Doug Stull's avatar Doug Stull Committed by Phil Hughes

Add invite option to reviewer dropdown [RUN AS-IF-FOSS]

parent 64f5f4c3
...@@ -2,12 +2,13 @@ import Vue from 'vue'; ...@@ -2,12 +2,13 @@ import Vue from 'vue';
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue'; import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
export default function initInviteMembersTrigger() { export default function initInviteMembersTrigger() {
const el = document.querySelector('.js-invite-members-trigger'); const triggers = document.querySelectorAll('.js-invite-members-trigger');
if (!el) { if (!triggers) {
return false; return false;
} }
return triggers.forEach((el) => {
return new Vue({ return new Vue({
el, el,
render: (createElement) => render: (createElement) =>
...@@ -17,4 +18,5 @@ export default function initInviteMembersTrigger() { ...@@ -17,4 +18,5 @@ export default function initInviteMembersTrigger() {
}, },
}), }),
}); });
});
} }
import loadAwardsHandler from '~/awards_handler'; import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import initIssuableSidebar from '~/init_issuable_sidebar'; import initIssuableSidebar from '~/init_issuable_sidebar';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { IssuableType } from '~/issuable_show/constants'; import { IssuableType } from '~/issuable_show/constants';
import Issue from '~/issue'; import Issue from '~/issue';
import '~/notes/index'; import '~/notes/index';
...@@ -34,8 +32,6 @@ export default function initShowIssue() { ...@@ -34,8 +32,6 @@ export default function initShowIssue() {
initIssueHeaderActions(store); initIssueHeaderActions(store);
initSentryErrorStackTraceApp(); initSentryErrorStackTraceApp();
initRelatedMergeRequestsApp(); initRelatedMergeRequestsApp();
initInviteMembersModal();
initInviteMembersTrigger();
import(/* webpackChunkName: 'design_management' */ '~/design_management') import(/* webpackChunkName: 'design_management' */ '~/design_management')
.then((module) => module.default()) .then((module) => module.default())
......
...@@ -4,8 +4,6 @@ import loadAwardsHandler from '~/awards_handler'; ...@@ -4,8 +4,6 @@ import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import initPipelines from '~/commit/pipelines/pipelines_bundle'; import initPipelines from '~/commit/pipelines/pipelines_bundle';
import initIssuableSidebar from '~/init_issuable_sidebar'; import initIssuableSidebar from '~/init_issuable_sidebar';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import StatusBox from '~/issuable/components/status_box.vue'; import StatusBox from '~/issuable/components/status_box.vue';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import { handleLocationHash } from '~/lib/utils/common_utils'; import { handleLocationHash } from '~/lib/utils/common_utils';
...@@ -29,8 +27,6 @@ export default function initMergeRequestShow() { ...@@ -29,8 +27,6 @@ export default function initMergeRequestShow() {
} else { } else {
loadAwardsHandler(); loadAwardsHandler();
} }
initInviteMembersModal();
initInviteMembersTrigger();
const el = document.querySelector('.js-mr-status-box'); const el = document.querySelector('.js-mr-status-box');
const apolloProvider = new VueApollo({ defaultClient: createDefaultClient() }); const apolloProvider = new VueApollo({ defaultClient: createDefaultClient() });
......
...@@ -2,6 +2,8 @@ import $ from 'jquery'; ...@@ -2,6 +2,8 @@ import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createFlash from '~/flash'; import createFlash from '~/flash';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
import initInviteMembersTrigger from '~/invite_members/init_invite_members_trigger';
import { IssuableType } from '~/issue_show/constants'; import { IssuableType } from '~/issue_show/constants';
import { import {
isInIssuePage, isInIssuePage,
...@@ -17,6 +19,7 @@ import SidebarDueDateWidget from '~/sidebar/components/date/sidebar_date_widget. ...@@ -17,6 +19,7 @@ import SidebarDueDateWidget from '~/sidebar/components/date/sidebar_date_widget.
import SidebarParticipantsWidget from '~/sidebar/components/participants/sidebar_participants_widget.vue'; import SidebarParticipantsWidget from '~/sidebar/components/participants/sidebar_participants_widget.vue';
import SidebarReferenceWidget from '~/sidebar/components/reference/sidebar_reference_widget.vue'; import SidebarReferenceWidget from '~/sidebar/components/reference/sidebar_reference_widget.vue';
import { apolloProvider } from '~/sidebar/graphql'; import { apolloProvider } from '~/sidebar/graphql';
import trackShowInviteMemberLink from '~/sidebar/track_invite_members';
import Translate from '../vue_shared/translate'; import Translate from '../vue_shared/translate';
import SidebarAssignees from './components/assignees/sidebar_assignees.vue'; import SidebarAssignees from './components/assignees/sidebar_assignees.vue';
import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue'; import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue';
...@@ -123,6 +126,12 @@ function mountAssigneesComponent() { ...@@ -123,6 +126,12 @@ function mountAssigneesComponent() {
}, },
}), }),
}); });
const assigneeDropdown = document.querySelector('.js-sidebar-assignee-dropdown');
if (assigneeDropdown) {
trackShowInviteMemberLink(assigneeDropdown);
}
} }
function mountReviewersComponent(mediator) { function mountReviewersComponent(mediator) {
...@@ -149,6 +158,12 @@ function mountReviewersComponent(mediator) { ...@@ -149,6 +158,12 @@ function mountReviewersComponent(mediator) {
}, },
}), }),
}); });
const reviewerDropdown = document.querySelector('.js-sidebar-reviewer-dropdown');
if (reviewerDropdown) {
trackShowInviteMemberLink(reviewerDropdown);
}
} }
export function mountSidebarLabels() { export function mountSidebarLabels() {
...@@ -438,6 +453,9 @@ const isAssigneesWidgetShown = ...@@ -438,6 +453,9 @@ const isAssigneesWidgetShown =
(isInIssuePage() || isInDesignPage()) && gon.features.issueAssigneesWidget; (isInIssuePage() || isInDesignPage()) && gon.features.issueAssigneesWidget;
export function mountSidebar(mediator) { export function mountSidebar(mediator) {
initInviteMembersModal();
initInviteMembersTrigger();
if (isAssigneesWidgetShown) { if (isAssigneesWidgetShown) {
mountAssigneesComponent(); mountAssigneesComponent();
} else { } else {
......
import $ from 'jquery'; import $ from 'jquery';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
export default function initTrackInviteMembers(assigneeDropdown) { export default function initTrackInviteMembers(userDropdown) {
const trackLabel = 'edit_assignee'; const { trackEvent, trackLabel } = userDropdown.querySelector('.js-invite-members-track').dataset;
const { trackEvent } = assigneeDropdown.querySelector('.js-invite-members-track').dataset;
$(assigneeDropdown).on('shown.bs.dropdown', () => { $(userDropdown).on('shown.bs.dropdown', () => {
Tracking.event(undefined, trackEvent, { Tracking.event(undefined, trackEvent, {
label: trackLabel, label: trackLabel,
}); });
......
...@@ -42,22 +42,7 @@ ...@@ -42,22 +42,7 @@
- data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select'] - data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select']
- options[:data].merge!(data) - options[:data].merge!(data)
- if directly_invite_members? = render 'shared/issuable/sidebar_user_dropdown',
- options[:dropdown_class] += ' dropdown-extended-height' options: options,
- options[:footer_content] = true wrapper_class: 'js-sidebar-assignee-dropdown',
- options[:wrapper_class] = 'js-sidebar-assignee-dropdown' track_label: 'edit_assignee'
- options[:toggle_class] += ' js-invite-members-track'
- data['track-event'] = 'show_invite_members'
- options[:data].merge!(data)
- invite_text = _('Invite Members')
- track_label = 'edit_assignee'
= dropdown_tag(title, options: options) do
%ul.dropdown-footer-list
%li
.js-invite-members-trigger{ data: { trigger_element: 'anchor',
display_text: invite_text,
event: 'click_invite_members',
label: track_label } }
- else
= dropdown_tag(title, options: options)
...@@ -39,4 +39,7 @@ ...@@ -39,4 +39,7 @@
- data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select'] - data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select']
- options[:data].merge!(data) - options[:data].merge!(data)
= dropdown_tag(title, options: options) = render 'shared/issuable/sidebar_user_dropdown',
options: options,
wrapper_class: 'js-sidebar-reviewer-dropdown',
track_label: 'edit_reviewer'
- options = local_assigns.fetch(:options)
- data = options[:data]
- if directly_invite_members?
- options[:dropdown_class] += ' dropdown-extended-height'
- options[:footer_content] = true
- options[:wrapper_class] = local_assigns.fetch(:wrapper_class)
- options[:toggle_class] += ' js-invite-members-track'
- data['track-event'] = 'show_invite_members'
- data['track-label'] = local_assigns.fetch(:track_label)
= dropdown_tag(data['dropdown-title'], options: options) do
%ul.dropdown-footer-list
%li
.js-invite-members-trigger{ data: { trigger_element: 'anchor',
display_text: _('Invite Members'),
event: 'click_invite_members',
label: data['track-label'] } }
- else
= dropdown_tag(data['dropdown-title'], options: options)
import trackShowInviteMemberLink from 'ee/projects/track_invite_members';
import initSidebarBundle from 'ee/sidebar/sidebar_bundle'; import initSidebarBundle from 'ee/sidebar/sidebar_bundle';
import initShow from '~/pages/projects/issues/show'; import initShow from '~/pages/projects/issues/show';
...@@ -13,7 +12,3 @@ initRelatedIssues(); ...@@ -13,7 +12,3 @@ initRelatedIssues();
new UserCallout({ className: 'js-epics-sidebar-callout' }); new UserCallout({ className: 'js-epics-sidebar-callout' });
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new UserCallout({ className: 'js-weight-sidebar-callout' }); new UserCallout({ className: 'js-weight-sidebar-callout' });
const assigneeDropdown = document.querySelector('.js-sidebar-assignee-dropdown');
if (assigneeDropdown) trackShowInviteMemberLink(assigneeDropdown);
import trackShowInviteMemberLink from 'ee/projects/track_invite_members';
import initSidebarBundle from 'ee/sidebar/sidebar_bundle'; import initSidebarBundle from 'ee/sidebar/sidebar_bundle';
import { initReviewBar } from '~/batch_comments'; import { initReviewBar } from '~/batch_comments';
import initMrNotes from '~/mr_notes'; import initMrNotes from '~/mr_notes';
...@@ -11,7 +10,3 @@ initSidebarBundle(); ...@@ -11,7 +10,3 @@ initSidebarBundle();
initMrNotes(); initMrNotes();
initReviewBar(); initReviewBar();
initIssuableHeaderWarning(store); initIssuableHeaderWarning(store);
const assigneeDropdown = document.querySelector('.js-sidebar-assignee-dropdown');
if (assigneeDropdown) trackShowInviteMemberLink(assigneeDropdown);
...@@ -32,7 +32,7 @@ RSpec.describe 'Issue Sidebar' do ...@@ -32,7 +32,7 @@ RSpec.describe 'Issue Sidebar' do
stub_feature_flags(issue_assignees_widget: false) stub_feature_flags(issue_assignees_widget: false)
end end
include_examples 'issuable invite members experiments' do include_examples 'issuable invite members' do
let(:issuable_path) { project_issue_path(project, issue2) } let(:issuable_path) { project_issue_path(project, issue2) }
end end
......
...@@ -68,14 +68,14 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js do ...@@ -68,14 +68,14 @@ RSpec.describe 'Merge request > User edits assignees sidebar', :js do
end end
end end
context 'with invite members experiment considerations' do context 'with invite members considerations' do
let_it_be(:user) { create(:user) } let_it_be(:user) { create(:user) }
before do before do
sign_in(user) sign_in(user)
end end
include_examples 'issuable invite members experiments' do include_examples 'issuable invite members' do
let(:issuable_path) { project_merge_request_path(project, merge_request) } let(:issuable_path) { project_merge_request_path(project, merge_request) }
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Merge request > User edits reviewers sidebar', :js do
context 'with invite members considerations' do
let_it_be(:merge_request) { create(:merge_request) }
let_it_be(:project) { merge_request.project }
let_it_be(:user) { create(:user) }
before do
sign_in(user)
end
context 'when a privileged user can invite in reviewer dropdown' do
before do
project.add_maintainer(user)
end
it 'shows a link for inviting members and launches invite modal' do
visit project_merge_request_path(project, merge_request)
reviewer_edit_link.click
wait_for_requests
page.within '.dropdown-menu-user' do
expect(page).to have_link('Invite Members')
expect(page).to have_selector('[data-track-event="click_invite_members"]')
expect(page).to have_selector('[data-track-label="edit_reviewer"]')
end
click_link 'Invite Members'
expect(page).to have_content("You're inviting members to the")
end
end
context 'when user cannot invite members in reviewer dropdown' do
before do
project.add_developer(user)
end
it 'shows author in assignee dropdown and no invite link' do
visit project_merge_request_path(project, merge_request)
reviewer_edit_link.click
wait_for_requests
page.within '.dropdown-menu-user' do
expect(page).not_to have_link('Invite Members')
end
end
end
def reviewer_edit_link
find('.block.reviewer .edit-link')
end
end
end
import $ from 'jquery'; import $ from 'jquery';
import trackShowInviteMemberLink from 'ee/projects/track_invite_members';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import trackShowInviteMemberLink from '~/sidebar/track_invite_members';
describe('Track user dropdown open', () => { describe('Track user dropdown open', () => {
let trackingSpy; let trackingSpy;
...@@ -10,7 +10,7 @@ describe('Track user dropdown open', () => { ...@@ -10,7 +10,7 @@ describe('Track user dropdown open', () => {
document.body.innerHTML = ` document.body.innerHTML = `
<div id="dummy-wrapper-element"> <div id="dummy-wrapper-element">
<div class="js-sidebar-assignee-dropdown"> <div class="js-sidebar-assignee-dropdown">
<div class="js-invite-members-track" data-track-event="_track_event_"> <div class="js-invite-members-track" data-track-event="_track_event_" data-track-label="_track_label_">
</div> </div>
</div> </div>
</div> </div>
...@@ -31,7 +31,7 @@ describe('Track user dropdown open', () => { ...@@ -31,7 +31,7 @@ describe('Track user dropdown open', () => {
$(dropdownElement).trigger('shown.bs.dropdown'); $(dropdownElement).trigger('shown.bs.dropdown');
expect(trackingSpy).toHaveBeenCalledWith(undefined, '_track_event_', { expect(trackingSpy).toHaveBeenCalledWith(undefined, '_track_event_', {
label: 'edit_assignee', label: '_track_label_',
}); });
}); });
}); });
# frozen_string_literal: true # frozen_string_literal: true
RSpec.shared_examples 'issuable invite members experiments' do RSpec.shared_examples 'issuable invite members' do
context 'when a privileged user can invite' do context 'when a privileged user can invite' do
it 'shows a link for inviting members and launches invite modal' do before do
project.add_maintainer(user) project.add_maintainer(user)
end
it 'shows a link for inviting members and launches invite modal' do
visit issuable_path visit issuable_path
find('.block.assignee .edit-link').click find('.block.assignee .edit-link').click
...@@ -23,8 +26,11 @@ RSpec.shared_examples 'issuable invite members experiments' do ...@@ -23,8 +26,11 @@ RSpec.shared_examples 'issuable invite members experiments' do
end end
context 'when user cannot invite members in assignee dropdown' do context 'when user cannot invite members in assignee dropdown' do
it 'shows author in assignee dropdown and no invite link' do before do
project.add_developer(user) project.add_developer(user)
end
it 'shows author in assignee dropdown and no invite link' do
visit issuable_path visit issuable_path
find('.block.assignee .edit-link').click find('.block.assignee .edit-link').click
......
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