Commit 22e368b2 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch '199698-smart-member-suggestions' into 'master'

Make smarter suggestion for assign commands

Closes #199698

See merge request gitlab-org/gitlab!24294
parents 19aab6fe 4dc71e3b
import $ from 'jquery';
import 'at.js';
import _ from 'underscore';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import glRegexp from './lib/utils/regexp';
import AjaxCache from './lib/utils/ajax_cache';
import { spriteIcon } from './lib/utils/common_utils';
......@@ -53,8 +54,8 @@ export const defaultAutocompleteConfig = {
};
class GfmAutoComplete {
constructor(dataSources) {
this.dataSources = dataSources || {};
constructor(dataSources = {}) {
this.dataSources = dataSources;
this.cachedData = {};
this.isLoadingData = {};
}
......@@ -199,6 +200,16 @@ class GfmAutoComplete {
}
setupMembers($input) {
const fetchData = this.fetchData.bind(this);
const MEMBER_COMMAND = {
ASSIGN: '/assign',
UNASSIGN: '/unassign',
REASSIGN: '/reassign',
CC: '/cc',
};
let assignees = [];
let command = '';
// Team Members
$input.atwho({
at: '@',
......@@ -225,6 +236,48 @@ class GfmAutoComplete {
callbacks: {
...this.getDefaultCallbacks(),
beforeSave: membersBeforeSave,
matcher(flag, subtext) {
const subtextNodes = subtext
.split(/\n+/g)
.pop()
.split(GfmAutoComplete.regexSubtext);
// Check if @ is followed by '/assign', '/reassign', '/unassign' or '/cc' commands.
command = subtextNodes.find(node => {
if (Object.values(MEMBER_COMMAND).includes(node)) {
return node;
}
return null;
});
// Cache assignees list for easier filtering later
assignees = SidebarMediator.singleton?.store?.assignees?.map(
assignee => `${assignee.username} ${assignee.name}`,
);
const match = GfmAutoComplete.defaultMatcher(flag, subtext, this.app.controllers);
return match && match.length ? match[1] : null;
},
filter(query, data, searchKey) {
if (GfmAutoComplete.isLoading(data)) {
fetchData(this.$inputor, this.at);
return data;
}
if (data === GfmAutoComplete.defaultLoadingData) {
return $.fn.atwho.default.callbacks.filter(query, data, searchKey);
}
if (command === MEMBER_COMMAND.ASSIGN) {
// Only include members which are not assigned to Issuable currently
return data.filter(member => !assignees.includes(member.search));
} else if (command === MEMBER_COMMAND.UNASSIGN) {
// Only include members which are assigned to Issuable currently
return data.filter(member => assignees.includes(member.search));
}
return data;
},
},
});
}
......
---
title: Make smarter user suggestions for assign slash commands
merge_request: 24294
author:
type: added
# frozen_string_literal: true
require 'spec_helper'
describe 'GFM autocomplete EE', :js do
let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let(:another_user) { create(:user, name: 'another user', username: 'another.user') }
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
before do
project.add_maintainer(user)
end
context 'assignees' do
let(:issue_assignee) { create(:issue, project: project) }
before do
issue_assignee.update(assignees: [user])
sign_in(user)
visit project_issue_path(project, issue_assignee)
wait_for_requests
end
it 'only lists users who are currently assigned to the issue when using /unassign' do
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('/una')
end
find('.atwho-view li', text: '/unassign')
note.native.send_keys(:tab)
wait_for_requests
users = find('#at-view-users .atwho-view-ul')
expect(users).to have_content(user.username)
expect(users).not_to have_content(another_user.username)
end
end
end
......@@ -282,6 +282,32 @@ describe 'GFM autocomplete', :js do
end
end
context 'assignees' do
let(:issue_assignee) { create(:issue, project: project) }
before do
issue_assignee.update(assignees: [user])
visit project_issue_path(project, issue_assignee)
wait_for_requests
end
it 'lists users who are currently not assigned to the issue when using /assign' do
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('/as')
end
find('.atwho-view li', text: '/assign')
note.native.send_keys(:tab)
wait_for_requests
expect(find('#at-view-users .atwho-view-ul')).not_to have_content(user.username)
end
end
context 'labels' do
it 'opens autocomplete menu for Labels when field starts with text with item escaping HTML characters' do
create(:label, project: project, title: label_xss_title)
......
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