Commit 6254a0bb authored by Coung Ngo's avatar Coung Ngo Committed by Jacques Erasmus

Add epic autocompletion to GfmAutocomplete component

Add epic autocompletion as part of migrating from jQuery-based
at.js to tribute
parent 2fdd4ce2
<script> <script>
import Tribute from 'tributejs'; import Tribute from 'tributejs';
import {
GfmAutocompleteType,
tributeConfig,
} from 'ee_else_ce/vue_shared/components/gfm_autocomplete/utils';
import createFlash from '~/flash'; import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import SidebarMediator from '~/sidebar/sidebar_mediator'; import SidebarMediator from '~/sidebar/sidebar_mediator';
import { GfmAutocompleteType, tributeConfig } from '~/vue_shared/components/gfm_autocomplete/utils';
export default { export default {
errorMessage: __( errorMessage: __(
......
...@@ -24,7 +24,7 @@ export const tributeConfig = { ...@@ -24,7 +24,7 @@ export const tributeConfig = {
[GfmAutocompleteType.Issues]: { [GfmAutocompleteType.Issues]: {
config: { config: {
trigger: '#', trigger: '#',
lookup: value => value.iid + value.title, lookup: value => `${value.iid}${value.title}`,
menuItemTemplate: ({ original }) => menuItemTemplate: ({ original }) =>
`<small>${original.reference || original.iid}</small> ${escape(original.title)}`, `<small>${original.reference || original.iid}</small> ${escape(original.title)}`,
selectTemplate: ({ original }) => original.reference || `#${original.iid}`, selectTemplate: ({ original }) => original.reference || `#${original.iid}`,
...@@ -61,7 +61,7 @@ export const tributeConfig = { ...@@ -61,7 +61,7 @@ export const tributeConfig = {
trigger: '@', trigger: '@',
fillAttr: 'username', fillAttr: 'username',
lookup: value => lookup: value =>
value.type === groupType ? last(value.name.split(' / ')) : value.name + value.username, value.type === groupType ? last(value.name.split(' / ')) : `${value.name}${value.username}`,
menuItemTemplate: ({ original }) => { menuItemTemplate: ({ original }) => {
const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0'; const commonClasses = 'gl-avatar gl-avatar-s24 gl-flex-shrink-0';
const noAvatarClasses = `${commonClasses} gl-rounded-small const noAvatarClasses = `${commonClasses} gl-rounded-small
...@@ -115,7 +115,7 @@ export const tributeConfig = { ...@@ -115,7 +115,7 @@ export const tributeConfig = {
[GfmAutocompleteType.MergeRequests]: { [GfmAutocompleteType.MergeRequests]: {
config: { config: {
trigger: '!', trigger: '!',
lookup: value => value.iid + value.title, lookup: value => `${value.iid}${value.title}`,
menuItemTemplate: ({ original }) => menuItemTemplate: ({ original }) =>
`<small>${original.reference || original.iid}</small> ${escape(original.title)}`, `<small>${original.reference || original.iid}</small> ${escape(original.title)}`,
selectTemplate: ({ original }) => original.reference || `!${original.iid}`, selectTemplate: ({ original }) => original.reference || `!${original.iid}`,
...@@ -135,7 +135,7 @@ export const tributeConfig = { ...@@ -135,7 +135,7 @@ export const tributeConfig = {
config: { config: {
trigger: '$', trigger: '$',
fillAttr: 'id', fillAttr: 'id',
lookup: value => value.id + value.title, lookup: value => `${value.id}${value.title}`,
menuItemTemplate: ({ original }) => `<small>${original.id}</small> ${escape(original.title)}`, menuItemTemplate: ({ original }) => `<small>${original.id}</small> ${escape(original.title)}`,
}, },
}, },
......
...@@ -173,7 +173,7 @@ export default { ...@@ -173,7 +173,7 @@ export default {
members: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, members: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
issues: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, issues: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
mergeRequests: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, mergeRequests: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
epics: this.enableAutocomplete, epics: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
milestones: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, milestones: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
labels: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, labels: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
snippets: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete, snippets: this.enableAutocomplete && !this.glFeatures.tributeAutocomplete,
......
import { escape } from 'lodash';
import {
GfmAutocompleteType as GfmAutocompleteTypeFoss,
tributeConfig as tributeConfigFoss,
} from '~/vue_shared/components/gfm_autocomplete/utils';
export const GfmAutocompleteType = {
...GfmAutocompleteTypeFoss,
Epics: 'epics',
};
export const tributeConfig = {
...tributeConfigFoss,
[GfmAutocompleteType.Epics]: {
config: {
trigger: '&',
fillAttr: 'iid',
lookup: value => `${value.iid}${value.title}`,
menuItemTemplate: ({ original }) =>
`<small>${original.iid}</small> ${escape(original.title)}`,
},
},
};
...@@ -3,10 +3,12 @@ ...@@ -3,10 +3,12 @@
require 'spec_helper' require 'spec_helper'
RSpec.describe 'GFM autocomplete EE', :js do RSpec.describe 'GFM autocomplete EE', :js do
let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') } let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let(:another_user) { create(:user, name: 'another user', username: 'another.user') } let_it_be(:another_user) { create(:user, name: 'another user', username: 'another.user') }
let(:project) { create(:project) } let_it_be(:group) { create(:group) }
let(:issue) { create(:issue, project: project) } let_it_be(:project) { create(:project, group: group) }
let_it_be(:issue) { create(:issue, project: project) }
let_it_be(:epic) { create(:epic, group: group) }
before do before do
project.add_maintainer(user) project.add_maintainer(user)
...@@ -46,6 +48,7 @@ RSpec.describe 'GFM autocomplete EE', :js do ...@@ -46,6 +48,7 @@ RSpec.describe 'GFM autocomplete EE', :js do
describe 'when tribute_autocomplete feature flag is on' do describe 'when tribute_autocomplete feature flag is on' do
before do before do
stub_licensed_features(epics: true)
stub_feature_flags(tribute_autocomplete: true) stub_feature_flags(tribute_autocomplete: true)
issue_assignee.update!(assignees: [user]) issue_assignee.update!(assignees: [user])
...@@ -72,6 +75,17 @@ RSpec.describe 'GFM autocomplete EE', :js do ...@@ -72,6 +75,17 @@ RSpec.describe 'GFM autocomplete EE', :js do
expect(users).to have_content(user.username) expect(users).to have_content(user.username)
expect(users).not_to have_content(another_user.username) expect(users).not_to have_content(another_user.username)
end end
it 'shows epics' do
note = find('#note-body')
page.within('.timeline-content-form') do
note.native.send_keys('&')
end
wait_for_requests
expect(find('.tribute-container ul', visible: true).text).to have_content(epic.title)
end
end end
end end
end end
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ee gfm_autocomplete/utils epics config shows the iid and title in the menu item 1`] = `"<small>123456</small> Epic title &lt;script&gt;alert(&#39;hi&#39;)&lt;/script&gt;"`;
import {
GfmAutocompleteType,
tributeConfig,
} from 'ee/vue_shared/components/gfm_autocomplete/utils';
describe('ee gfm_autocomplete/utils', () => {
describe('epics config', () => {
const epicsConfig = tributeConfig[GfmAutocompleteType.Epics].config;
const epic = {
id: null,
iid: 123456,
title: "Epic title <script>alert('hi')</script>",
};
it('uses & as the trigger', () => {
expect(epicsConfig.trigger).toBe('&');
});
it('inserts the iid on autocomplete selection', () => {
expect(epicsConfig.fillAttr).toBe('iid');
});
it('searches using both the iid and title', () => {
expect(epicsConfig.lookup(epic)).toBe(`${epic.iid}${epic.title}`);
});
it('shows the iid and title in the menu item', () => {
expect(epicsConfig.menuItemTemplate({ original: epic })).toMatchSnapshot();
});
});
});
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