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 @@