diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue index 2e00a23de7c5e509355d8a9beb12d65d3944cabb..af17ef0867df69ee29ed4b2fef2e5a8be3f3f335 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue @@ -22,6 +22,7 @@ import { issuableAttributesQueries, noAttributeId, defaultEpicSort, + epicIidPattern, } from '~/sidebar/constants'; export default { @@ -118,17 +119,37 @@ export default { return query; }, skip() { + if (this.isEpic && this.searchTerm.startsWith('&') && this.searchTerm.length < 2) { + return true; + } + return !this.editing; }, debounce: 250, variables() { - return { + if (!this.isEpic) { + return { + fullPath: this.attrWorkspacePath, + title: this.searchTerm, + state: this.$options.IssuableAttributeState[this.issuableAttribute], + }; + } + + const variables = { fullPath: this.attrWorkspacePath, - title: this.searchTerm, - in: this.searchTerm && this.issuableAttribute === IssuableType.Epic ? 'TITLE' : undefined, state: this.$options.IssuableAttributeState[this.issuableAttribute], - sort: this.issuableAttribute === IssuableType.Epic ? defaultEpicSort : null, + sort: defaultEpicSort, }; + + if (epicIidPattern.test(this.searchTerm)) { + const matches = this.searchTerm.match(epicIidPattern); + variables.iidStartsWith = matches.groups.iid; + } else if (this.searchTerm !== '') { + variables.in = 'TITLE'; + variables.title = this.searchTerm; + } + + return variables; }, update(data) { if (data?.workspace) { @@ -214,6 +235,9 @@ export default { ), }; }, + isEpic() { + return this.issuableAttribute === IssuableType.Epic; + }, }, methods: { updateAttribute(attributeId) { diff --git a/app/assets/javascripts/sidebar/constants.js b/app/assets/javascripts/sidebar/constants.js index 08ee4379c0c66ae08f46eb87db25dc09d0587c5f..fd43fb80b7f063e6932f5fa3f7a38ad3152ac026 100644 --- a/app/assets/javascripts/sidebar/constants.js +++ b/app/assets/javascripts/sidebar/constants.js @@ -48,6 +48,8 @@ export const ASSIGNEES_DEBOUNCE_DELAY = DEFAULT_DEBOUNCE_AND_THROTTLE_MS; export const defaultEpicSort = 'TITLE_ASC'; +export const epicIidPattern = /^&(?<iid>\d+)$/; + export const assigneesQueries = { [IssuableType.Issue]: { query: getIssueAssignees, diff --git a/ee/app/assets/javascripts/sidebar/queries/group_epics.query.graphql b/ee/app/assets/javascripts/sidebar/queries/group_epics.query.graphql index 75703f417e74adce49ba08fbaa35a9f5b2aae43f..e1cc6d423b7f1dda4519090c321f926955f50adb 100644 --- a/ee/app/assets/javascripts/sidebar/queries/group_epics.query.graphql +++ b/ee/app/assets/javascripts/sidebar/queries/group_epics.query.graphql @@ -5,6 +5,7 @@ query issueEpics( $title: String $state: EpicState $in: [IssuableSearchableField!] + $iidStartsWith: String ) { workspace: group(fullPath: $fullPath) { attributes: epics( @@ -13,6 +14,7 @@ query issueEpics( state: $state includeAncestorGroups: true includeDescendantGroups: false + iidStartsWith: $iidStartsWith ) { nodes { ...EpicFragment diff --git a/ee/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js b/ee/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js index aa809987a55e0eb839fcefa818e32a7f98b6c4c4..faf02c5a30d612db7e592cdc665ab0ccdd168a5b 100644 --- a/ee/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js +++ b/ee/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js @@ -452,7 +452,6 @@ describe('SidebarDropdownWidget', () => { fullPath: mockIssue.groupPath, sort: 'TITLE_ASC', state: 'opened', - title: '', }); }); @@ -501,8 +500,21 @@ describe('SidebarDropdownWidget', () => { fullPath: mockIssue.groupPath, sort: 'TITLE_ASC', state: 'opened', - title: '', - in: undefined, + }); + }); + + it('sends a groupEpics query for an IID with the entered search term "&1"', async () => { + findSearchBox().vm.$emit('input', '&1'); + await wrapper.vm.$nextTick(); + + // Account for debouncing + jest.runAllTimers(); + + expect(groupEpicsSpy).toHaveBeenNthCalledWith(2, { + fullPath: mockIssue.groupPath, + iidStartsWith: '1', + sort: 'TITLE_ASC', + state: 'opened', }); }); }); diff --git a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js index f5e5ab4a98496c4165ca2b684c655971e659041f..6355b3542cd1e56b705e8a2c8a4fdbf8e5204f23 100644 --- a/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js +++ b/spec/frontend/sidebar/components/sidebar_dropdown_widget_spec.js @@ -451,7 +451,6 @@ describe('SidebarDropdownWidget', () => { expect(projectMilestonesSpy).toHaveBeenNthCalledWith(1, { fullPath: mockIssue.projectPath, - sort: null, state: 'active', title: '', }); @@ -478,7 +477,6 @@ describe('SidebarDropdownWidget', () => { expect(projectMilestonesSpy).toHaveBeenNthCalledWith(2, { fullPath: mockIssue.projectPath, - sort: null, state: 'active', title: mockSearchTerm, });