Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/gfm_auto_complete.js')
-rw-r--r--app/assets/javascripts/gfm_auto_complete.js74
1 files changed, 72 insertions, 2 deletions
diff --git a/app/assets/javascripts/gfm_auto_complete.js b/app/assets/javascripts/gfm_auto_complete.js
index 69331ff1a06..bf29a356abd 100644
--- a/app/assets/javascripts/gfm_auto_complete.js
+++ b/app/assets/javascripts/gfm_auto_complete.js
@@ -86,6 +86,7 @@ export const defaultAutocompleteConfig = {
labels: true,
snippets: true,
vulnerabilities: true,
+ contacts: true,
};
class GfmAutoComplete {
@@ -127,6 +128,7 @@ class GfmAutoComplete {
if (this.enableMap.mergeRequests) this.setupMergeRequests($input);
if (this.enableMap.labels) this.setupLabels($input);
if (this.enableMap.snippets) this.setupSnippets($input);
+ if (this.enableMap.contacts) this.setupContacts($input);
$input.filter('[data-supports-quick-actions="true"]').atwho({
at: '/',
@@ -174,9 +176,16 @@ class GfmAutoComplete {
let tpl = '/${name} ';
let referencePrefix = null;
if (value.params.length > 0) {
- [[referencePrefix]] = value.params;
- if (/^[@%~]/.test(referencePrefix)) {
+ const regexp = /\[[a-z]+:/;
+ const match = regexp.exec(value.params);
+ if (match) {
+ [referencePrefix] = match;
tpl += '<%- referencePrefix %>';
+ } else {
+ [[referencePrefix]] = value.params;
+ if (/^[@%~]/.test(referencePrefix)) {
+ tpl += '<%- referencePrefix %>';
+ }
}
}
return template(tpl, { interpolate: /<%=([\s\S]+?)%>/g })({ referencePrefix });
@@ -266,6 +275,8 @@ class GfmAutoComplete {
UNASSIGN_REVIEWER: '/unassign_reviewer',
REASSIGN: '/reassign',
CC: '/cc',
+ ATTENTION: '/attention',
+ REMOVE_ATTENTION: '/remove_attention',
};
let assignees = [];
let reviewers = [];
@@ -344,6 +355,23 @@ class GfmAutoComplete {
} else if (command === MEMBER_COMMAND.UNASSIGN_REVIEWER) {
// Only include members which are not assigned as a reviewer to Issuable currently
return data.filter((member) => reviewers.includes(member.search));
+ } else if (
+ command === MEMBER_COMMAND.ATTENTION ||
+ command === MEMBER_COMMAND.REMOVE_ATTENTION
+ ) {
+ const attentionUsers = [
+ ...(SidebarMediator.singleton?.store?.assignees || []),
+ ...(SidebarMediator.singleton?.store?.reviewers || []),
+ ];
+ const attentionRequested = command === MEMBER_COMMAND.REMOVE_ATTENTION;
+
+ return data.filter((member) =>
+ attentionUsers.find(
+ (u) =>
+ createMemberSearchString(u).includes(member.search) &&
+ u.attention_requested === attentionRequested,
+ ),
+ );
}
return data;
@@ -619,6 +647,42 @@ class GfmAutoComplete {
});
}
+ setupContacts($input) {
+ $input.atwho({
+ at: '[contact:',
+ suffix: ']',
+ alias: 'contacts',
+ searchKey: 'search',
+ displayTpl(value) {
+ let tmpl = GfmAutoComplete.Loading.template;
+ if (value.email != null) {
+ tmpl = GfmAutoComplete.Contacts.templateFunction(value);
+ }
+ return tmpl;
+ },
+ data: GfmAutoComplete.defaultLoadingData,
+ // eslint-disable-next-line no-template-curly-in-string
+ insertTpl: '${atwho-at}${email}',
+ callbacks: {
+ ...this.getDefaultCallbacks(),
+ beforeSave(contacts) {
+ return $.map(contacts, (m) => {
+ if (m.email == null) {
+ return m;
+ }
+ return {
+ id: m.id,
+ email: m.email,
+ firstName: m.first_name,
+ lastName: m.last_name,
+ search: `${m.email}`,
+ };
+ });
+ },
+ },
+ });
+ }
+
getDefaultCallbacks() {
const self = this;
@@ -790,6 +854,7 @@ GfmAutoComplete.atTypeMap = {
'/': 'commands',
'[vulnerability:': 'vulnerabilities',
$: 'snippets',
+ '[contact:': 'contacts',
};
GfmAutoComplete.typesWithBackendFiltering = ['vulnerabilities'];
@@ -883,6 +948,11 @@ GfmAutoComplete.Milestones = {
return `<li>${escape(title)}</li>`;
},
};
+GfmAutoComplete.Contacts = {
+ templateFunction({ email, firstName, lastName }) {
+ return `<li><small>${firstName} ${lastName}</small> ${escape(email)}</li>`;
+ },
+};
GfmAutoComplete.Loading = {
template:
'<li style="pointer-events: none;"><span class="spinner align-text-bottom mr-1"></span>Loading...</li>',