diff --git a/.rubocop_todo/layout/argument_alignment.yml b/.rubocop_todo/layout/argument_alignment.yml index 5a145708439..66d5737ab9c 100644 --- a/.rubocop_todo/layout/argument_alignment.yml +++ b/.rubocop_todo/layout/argument_alignment.yml @@ -1574,20 +1574,6 @@ Layout/ArgumentAlignment: - 'spec/features/merge_request/user_merges_when_pipeline_succeeds_spec.rb' - 'spec/features/merge_request/user_opens_checkout_branch_modal_spec.rb' - 'spec/features/merge_request/user_posts_notes_spec.rb' - - 'spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb' - - 'spec/features/merge_request/user_resolves_outdated_diff_discussions_spec.rb' - - 'spec/features/merge_request/user_resolves_wip_mr_spec.rb' - - 'spec/features/merge_request/user_sees_deployment_widget_spec.rb' - - 'spec/features/merge_request/user_sees_discussions_navigation_spec.rb' - - 'spec/features/merge_request/user_sees_merge_button_depending_on_unresolved_discussions_spec.rb' - - 'spec/features/merge_request/user_sees_merge_request_pipelines_spec.rb' - - 'spec/features/merge_request/user_sees_merge_widget_spec.rb' - - 'spec/features/merge_request/user_sees_mr_from_deleted_forked_project_spec.rb' - - 'spec/features/merge_request/user_sees_mr_with_deleted_source_branch_spec.rb' - - 'spec/features/merge_request/user_sees_notes_from_forked_project_spec.rb' - - 'spec/features/merge_request/user_sees_pipelines_from_forked_project_spec.rb' - - 'spec/features/merge_request/user_sees_pipelines_spec.rb' - - 'spec/features/merge_request/user_sees_versions_spec.rb' - 'spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb' - 'spec/features/merge_request/user_squashes_merge_request_spec.rb' - 'spec/features/merge_request/user_suggests_changes_on_diff_spec.rb' diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue index 0151dbb0bf7..bd8a7257d0c 100644 --- a/app/assets/javascripts/error_tracking/components/error_details.vue +++ b/app/assets/javascripts/error_tracking/components/error_details.vue @@ -6,9 +6,7 @@ import { GlBadge, GlAlert, GlSprintf, - GlDropdown, - GlDropdownItem, - GlDropdownDivider, + GlDisclosureDropdown, } from '@gitlab/ui'; import { mapActions, mapGetters, mapState } from 'vuex'; import { createAlert, VARIANT_WARNING } from '~/alert'; @@ -38,9 +36,7 @@ export default { GlBadge, GlAlert, GlSprintf, - GlDropdown, - GlDropdownItem, - GlDropdownDivider, + GlDisclosureDropdown, TimeAgoTooltip, ErrorDetailsInfo, TimelineChart, @@ -167,6 +163,52 @@ export default { showEmptyStacktraceAlert() { return !this.loadingStacktrace && !this.showStacktrace && this.isStacktraceEmptyAlertVisible; }, + updateDropdownItems() { + return [ + { + text: this.ignoreBtnLabel, + action: this.onIgnoreStatusUpdate, + extraAttrs: { + 'data-qa-selector': 'update_ignore_status_button', + }, + }, + { + text: this.resolveBtnLabel, + action: this.onResolveStatusUpdate, + extraAttrs: { + 'data-qa-selector': 'update_resolve_status_button', + }, + }, + ]; + }, + viewIssueDropdownItem() { + return { + text: __('View issue'), + href: this.error.gitlabIssuePath, + extraAttrs: { + 'data-qa-selector': 'view_issue_button', + }, + }; + }, + createIssueDropdownItem() { + return { + text: __('Create issue'), + action: this.createIssue, + extraAttrs: { + 'data-qa-selector': 'create_issue_button', + }, + }; + }, + dropdownItems() { + return [ + { items: this.updateDropdownItems }, + { + items: [ + this.error.gitlabIssuePath ? this.viewIssueDropdownItem : this.createIssueDropdownItem, + ], + }, + ]; + }, }, watch: { error(val) { @@ -331,37 +373,14 @@ export default { - - {{ ignoreBtnLabel }} - {{ resolveBtnLabel }} - - {{ __('View issue') }} - {{ __('Create issue') }} - + :items="dropdownItems" + />
diff --git a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue index 96e6c9bab9e..b8921bd0bfa 100644 --- a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue +++ b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/command_palette_items.vue @@ -5,18 +5,20 @@ import { GlDisclosureDropdownGroup, GlLoadingIcon } from '@gitlab/ui'; import axios from '~/lib/utils/axios_utils'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import { getFormattedItem } from '../utils'; + import { COMMON_HANDLES, COMMAND_HANDLE, USER_HANDLE, PROJECT_HANDLE, ISSUE_HANDLE, - GLOBAL_COMMANDS_GROUP_TITLE, + PATH_HANDLE, PAGES_GROUP_TITLE, + PATH_GROUP_TITLE, GROUP_TITLES, } from './constants'; import SearchItem from './search_item.vue'; -import { commandMapper, linksReducer, autocompleteQuery } from './utils'; +import { commandMapper, linksReducer, autocompleteQuery, fileMapper } from './utils'; export default { name: 'CommandPaletteItems', @@ -25,7 +27,14 @@ export default { GlLoadingIcon, SearchItem, }, - inject: ['commandPaletteCommands', 'commandPaletteLinks', 'autocompletePath', 'searchContext'], + inject: [ + 'commandPaletteCommands', + 'commandPaletteLinks', + 'autocompletePath', + 'searchContext', + 'projectFilesPath', + 'projectBlobPath', + ], props: { searchQuery: { type: String, @@ -35,7 +44,7 @@ export default { type: String, required: true, validator: (value) => { - return COMMON_HANDLES.includes(value); + return [...COMMON_HANDLES, PATH_HANDLE].includes(value); }, }, }, @@ -43,13 +52,14 @@ export default { groups: [], error: null, loading: false, + projectFiles: [], }), computed: { isCommandMode() { return this.handle === COMMAND_HANDLE; }, - isUserMode() { - return this.handle === USER_HANDLE; + isPathMode() { + return this.handle === PATH_HANDLE; }, commands() { return this.commandPaletteCommands.map(commandMapper); @@ -62,7 +72,7 @@ export default { ? this.commands .map(({ name, items }) => { return { - name: name || GLOBAL_COMMANDS_GROUP_TITLE, + name, items: this.filterBySearchQuery(items, 'text'), }; }) @@ -73,7 +83,7 @@ export default { return this.groups?.length && this.groups.some((group) => group.items?.length); }, hasSearchQuery() { - if (this.isCommandMode) { + if (this.isCommandMode || this.isPathMode) { return this.searchQuery?.length > 0; } return this.searchQuery?.length > 2; @@ -84,6 +94,12 @@ export default { } return this.searchQuery; }, + filteredProjectFiles() { + if (!this.searchQuery) { + return this.projectFiles; + } + return this.filterBySearchQuery(this.projectFiles, 'text'); + }, }, watch: { searchQuery: { @@ -97,6 +113,9 @@ export default { case ISSUE_HANDLE: this.getScopedItems(); break; + case PATH_HANDLE: + this.getProjectFiles(); + break; default: break; } @@ -162,6 +181,26 @@ export default { }, ]; }, + async getProjectFiles() { + if (!this.projectFiles.length) { + this.loading = true; + try { + const response = await axios.get(this.projectFilesPath); + this.projectFiles = response?.data.map(fileMapper.bind(null, this.projectBlobPath)); + } catch (error) { + this.error = error; + } finally { + this.loading = false; + } + } + + this.groups = [ + { + name: PATH_GROUP_TITLE, + items: this.filteredProjectFiles, + }, + ]; + }, }, }; diff --git a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js index 9dab16984f5..780936c1b88 100644 --- a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js +++ b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/constants.js @@ -4,17 +4,19 @@ export const COMMAND_HANDLE = '>'; export const USER_HANDLE = '@'; export const PROJECT_HANDLE = '&'; export const ISSUE_HANDLE = '#'; +export const PATH_HANDLE = '/'; export const COMMON_HANDLES = [COMMAND_HANDLE, USER_HANDLE, PROJECT_HANDLE, ISSUE_HANDLE]; export const SEARCH_OR_COMMAND_MODE_PLACEHOLDER = sprintf( s__( - 'CommandPalette|Type %{commandHandle} for command, %{userHandle} for user, %{projectHandle} for project, %{issueHandle} for issue or perform generic search...', + 'CommandPalette|Type %{commandHandle} for command, %{userHandle} for user, %{projectHandle} for project, %{issueHandle} for issue, %{pathHandle} for project file or perform generic search...', ), { commandHandle: COMMAND_HANDLE, userHandle: USER_HANDLE, issueHandle: ISSUE_HANDLE, projectHandle: PROJECT_HANDLE, + pathHandle: PATH_HANDLE, }, false, ); @@ -24,6 +26,7 @@ export const SEARCH_SCOPE_PLACEHOLDER = { [USER_HANDLE]: s__('CommandPalette|user (enter at least 3 chars)'), [PROJECT_HANDLE]: s__('CommandPalette|project (enter at least 3 chars)'), [ISSUE_HANDLE]: s__('CommandPalette|issue (enter at least 3 chars)'), + [PATH_HANDLE]: s__('CommandPalette|go to project file'), }; export const SEARCH_SCOPE = { @@ -37,9 +40,11 @@ export const USERS_GROUP_TITLE = s__('GlobalSearch|Users'); export const PAGES_GROUP_TITLE = s__('CommandPalette|Pages'); export const PROJECTS_GROUP_TITLE = s__('GlobalSearch|Projects'); export const ISSUE_GROUP_TITLE = s__('GlobalSearch|Recent issues'); +export const PATH_GROUP_TITLE = s__('CommandPalette|Project files'); export const GROUP_TITLES = { [USER_HANDLE]: USERS_GROUP_TITLE, [PROJECT_HANDLE]: PROJECTS_GROUP_TITLE, [ISSUE_HANDLE]: ISSUE_GROUP_TITLE, + [PATH_HANDLE]: PATH_GROUP_TITLE, }; diff --git a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/fake_search_input.vue b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/fake_search_input.vue index dce2b24f551..efd93e88fa9 100644 --- a/app/assets/javascripts/super_sidebar/components/global_search/command_palette/fake_search_input.vue +++ b/app/assets/javascripts/super_sidebar/components/global_search/command_palette/fake_search_input.vue @@ -1,5 +1,5 @@