summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/gfm_autocomplete
diff options
context:
space:
mode:
authorRobert Speicher <rspeicher@gmail.com>2021-01-20 13:34:23 -0600
committerRobert Speicher <rspeicher@gmail.com>2021-01-20 13:34:23 -0600
commit6438df3a1e0fb944485cebf07976160184697d72 (patch)
tree00b09bfd170e77ae9391b1a2f5a93ef6839f2597 /app/assets/javascripts/vue_shared/components/gfm_autocomplete
parent42bcd54d971da7ef2854b896a7b34f4ef8601067 (diff)
downloadgitlab-ce-6438df3a1e0fb944485cebf07976160184697d72.tar.gz
Add latest changes from gitlab-org/gitlab@13-8-stable-eev13.8.0-rc42
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/gfm_autocomplete')
-rw-r--r--app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue15
-rw-r--r--app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js69
2 files changed, 73 insertions, 11 deletions
diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue
index 1ad0ca36bf8..9ab91e567e6 100644
--- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue
+++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/gfm_autocomplete.vue
@@ -4,6 +4,7 @@ import {
GfmAutocompleteType,
tributeConfig,
} from 'ee_else_ce/vue_shared/components/gfm_autocomplete/utils';
+import * as Emoji from '~/emoji';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -27,7 +28,7 @@ export default {
},
computed: {
config() {
- return this.autocompleteTypes.map(type => ({
+ return this.autocompleteTypes.map((type) => ({
...tributeConfig[type].config,
loadingItemTemplate: `<span class="gl-spinner gl-vertical-align-text-bottom gl-ml-3 gl-mr-2"></span>${__(
'Loading',
@@ -55,7 +56,7 @@ export default {
if (!this.assignees || !isAssigneesLengthSame) {
this.assignees =
- SidebarMediator.singleton?.store?.assignees?.map(assignee => assignee.username) || [];
+ SidebarMediator.singleton?.store?.assignees?.map((assignee) => assignee.username) || [];
}
},
filterValues(type) {
@@ -76,10 +77,18 @@ export default {
return (inputText, processValues) => {
if (this.cache[type]) {
processValues(this.filterValues(type));
+ } else if (type === GfmAutocompleteType.Emojis) {
+ Emoji.initEmojiMap()
+ .then(() => {
+ const emojis = Emoji.getValidEmojiNames();
+ this.cache[type] = emojis;
+ processValues(emojis);
+ })
+ .catch(() => createFlash({ message: this.$options.errorMessage }));
} else if (this.dataSources[type]) {
axios
.get(this.dataSources[type])
- .then(response => {
+ .then((response) => {
this.cache[type] = response.data;
processValues(this.filterValues(type));
})
diff --git a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js
index 2581888b504..809932b0f29 100644
--- a/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js
+++ b/app/assets/javascripts/vue_shared/components/gfm_autocomplete/utils.js
@@ -1,16 +1,24 @@
import { escape, last } from 'lodash';
+import * as Emoji from '~/emoji';
import { spriteIcon } from '~/lib/utils/common_utils';
const groupType = 'Group'; // eslint-disable-line @gitlab/require-i18n-strings
+// Number of users to show in the autocomplete menu to avoid doing a mass fetch of 100+ avatars
+const memberLimit = 10;
+
const nonWordOrInteger = /\W|^\d+$/;
+export const menuItemLimit = 100;
+
export const GfmAutocompleteType = {
+ Emojis: 'emojis',
Issues: 'issues',
Labels: 'labels',
Members: 'members',
MergeRequests: 'mergeRequests',
Milestones: 'milestones',
+ QuickActions: 'commands',
Snippets: 'snippets',
};
@@ -21,10 +29,21 @@ function doesCurrentLineStartWith(searchString, fullText, selectionStart) {
}
export const tributeConfig = {
+ [GfmAutocompleteType.Emojis]: {
+ config: {
+ trigger: ':',
+ lookup: (value) => value,
+ menuItemLimit,
+ menuItemTemplate: ({ original }) => `${original} ${Emoji.glEmojiTag(original)}`,
+ selectTemplate: ({ original }) => `:${original}:`,
+ },
+ },
+
[GfmAutocompleteType.Issues]: {
config: {
trigger: '#',
- lookup: value => `${value.iid}${value.title}`,
+ lookup: (value) => `${value.iid}${value.title}`,
+ menuItemLimit,
menuItemTemplate: ({ original }) =>
`<small>${original.reference || original.iid}</small> ${escape(original.title)}`,
selectTemplate: ({ original }) => original.reference || `#${original.iid}`,
@@ -35,6 +54,7 @@ export const tributeConfig = {
config: {
trigger: '~',
lookup: 'title',
+ menuItemLimit,
menuItemTemplate: ({ original }) => `
<span class="dropdown-label-box" style="background: ${escape(original.color)};"></span>
${escape(original.title)}`,
@@ -45,11 +65,11 @@ export const tributeConfig = {
},
filterValues({ collection, fullText, selectionStart }) {
if (doesCurrentLineStartWith('/label', fullText, selectionStart)) {
- return collection.filter(label => !label.set);
+ return collection.filter((label) => !label.set);
}
if (doesCurrentLineStartWith('/unlabel', fullText, selectionStart)) {
- return collection.filter(label => label.set);
+ return collection.filter((label) => label.set);
}
return collection;
@@ -60,8 +80,9 @@ export const tributeConfig = {
config: {
trigger: '@',
fillAttr: 'username',
- lookup: value =>
+ lookup: (value) =>
value.type === groupType ? last(value.name.split(' / ')) : `${value.name}${value.username}`,
+ menuItemLimit: memberLimit,
menuItemTemplate: ({ original }) => {
const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0';
const noAvatarClasses = `${commonClasses} gl-rounded-small
@@ -101,11 +122,11 @@ export const tributeConfig = {
},
filterValues({ assignees, collection, fullText, selectionStart }) {
if (doesCurrentLineStartWith('/assign', fullText, selectionStart)) {
- return collection.filter(member => !assignees.includes(member.username));
+ return collection.filter((member) => !assignees.includes(member.username));
}
if (doesCurrentLineStartWith('/unassign', fullText, selectionStart)) {
- return collection.filter(member => assignees.includes(member.username));
+ return collection.filter((member) => assignees.includes(member.username));
}
return collection;
@@ -115,7 +136,8 @@ export const tributeConfig = {
[GfmAutocompleteType.MergeRequests]: {
config: {
trigger: '!',
- lookup: value => `${value.iid}${value.title}`,
+ lookup: (value) => `${value.iid}${value.title}`,
+ menuItemLimit,
menuItemTemplate: ({ original }) =>
`<small>${original.reference || original.iid}</small> ${escape(original.title)}`,
selectTemplate: ({ original }) => original.reference || `!${original.iid}`,
@@ -126,16 +148,47 @@ export const tributeConfig = {
config: {
trigger: '%',
lookup: 'title',
+ menuItemLimit,
menuItemTemplate: ({ original }) => escape(original.title),
selectTemplate: ({ original }) => `%"${escape(original.title)}"`,
},
},
+ [GfmAutocompleteType.QuickActions]: {
+ config: {
+ trigger: '/',
+ fillAttr: 'name',
+ lookup: (value) => `${value.name}${value.aliases.join()}`,
+ menuItemLimit,
+ menuItemTemplate: ({ original }) => {
+ const aliases = original.aliases.length
+ ? `<small>(or /${original.aliases.join(', /')})</small>`
+ : '';
+
+ const params = original.params.length ? `<small>${original.params.join(' ')}</small>` : '';
+
+ let description = '';
+
+ if (original.warning) {
+ const confidentialIcon =
+ original.icon === 'confidential' ? spriteIcon('eye-slash', 's16 gl-mr-2') : '';
+ description = `<small>${confidentialIcon}<em>${original.warning}</em></small>`;
+ } else if (original.description) {
+ description = `<small><em>${original.description}</em></small>`;
+ }
+
+ return `<div>/${original.name} ${aliases} ${params}</div>
+ <div>${description}</div>`;
+ },
+ },
+ },
+
[GfmAutocompleteType.Snippets]: {
config: {
trigger: '$',
fillAttr: 'id',
- lookup: value => `${value.id}${value.title}`,
+ lookup: (value) => `${value.id}${value.title}`,
+ menuItemLimit,
menuItemTemplate: ({ original }) => `<small>${original.id}</small> ${escape(original.title)}`,
},
},