diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-29 09:11:43 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-09-29 09:11:43 +0000 |
commit | c724e639a91a4d112b7f0a05b3c6a0ffa6baa7a4 (patch) | |
tree | dccd51e5f480459820f1f908ad22584e8fe8689c /app/assets/javascripts/issues_list | |
parent | cba55463a02fe6f9c9e8b6ed0b9ed38a0f087342 (diff) | |
download | gitlab-ce-c724e639a91a4d112b7f0a05b3c6a0ffa6baa7a4.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/issues_list')
4 files changed, 148 insertions, 0 deletions
diff --git a/app/assets/javascripts/issues_list/components/issues_list_app.vue b/app/assets/javascripts/issues_list/components/issues_list_app.vue index 8e37339fca6..de57cb93899 100644 --- a/app/assets/javascripts/issues_list/components/issues_list_app.vue +++ b/app/assets/javascripts/issues_list/components/issues_list_app.vue @@ -82,6 +82,7 @@ import searchLabelsQuery from '../queries/search_labels.query.graphql'; import searchMilestonesQuery from '../queries/search_milestones.query.graphql'; import searchUsersQuery from '../queries/search_users.query.graphql'; import IssueCardTimeInfo from './issue_card_time_info.vue'; +import NewIssueDropdown from './new_issue_dropdown.vue'; export default { i18n, @@ -96,6 +97,7 @@ export default { IssuableByEmail, IssuableList, IssueCardTimeInfo, + NewIssueDropdown, BlockingIssuesCount: () => import('ee_component/issues/components/blocking_issues_count.vue'), }, directives: { @@ -126,6 +128,9 @@ export default { hasAnyIssues: { default: false, }, + hasAnyProjects: { + default: false, + }, hasBlockedIssuesFeature: { default: false, }, @@ -253,6 +258,9 @@ export default { showCsvButtons() { return this.isProject && this.isSignedIn; }, + showNewIssueDropdown() { + return !this.isProject && this.hasAnyProjects; + }, apiFilterParams() { return convertToApiParams(this.filterTokens); }, @@ -662,6 +670,7 @@ export default { <gl-button v-if="showNewIssueLink" :href="newIssuePath" variant="confirm"> {{ $options.i18n.newIssueLabel }} </gl-button> + <new-issue-dropdown v-if="showNewIssueDropdown" /> </template> <template #timeframe="{ issuable = {} }"> @@ -765,6 +774,7 @@ export default { :export-csv-path="exportCsvPathWithQuery" :issuable-count="currentTabCount" /> + <new-issue-dropdown v-if="showNewIssueDropdown" /> </template> </gl-empty-state> <hr /> diff --git a/app/assets/javascripts/issues_list/components/new_issue_dropdown.vue b/app/assets/javascripts/issues_list/components/new_issue_dropdown.vue new file mode 100644 index 00000000000..037fd9be542 --- /dev/null +++ b/app/assets/javascripts/issues_list/components/new_issue_dropdown.vue @@ -0,0 +1,124 @@ +<script> +import { + GlDropdown, + GlDropdownItem, + GlDropdownText, + GlLoadingIcon, + GlSearchBoxByType, +} from '@gitlab/ui'; +import createFlash from '~/flash'; +import searchProjectsQuery from '~/issues_list/queries/search_projects.query.graphql'; +import { DASH_SCOPE, joinPaths } from '~/lib/utils/url_utility'; +import { __, sprintf } from '~/locale'; +import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants'; + +export default { + i18n: { + defaultDropdownText: __('Select project to create issue'), + noMatchesFound: __('No matches found'), + toggleButtonLabel: __('Toggle project select'), + }, + components: { + GlDropdown, + GlDropdownItem, + GlDropdownText, + GlLoadingIcon, + GlSearchBoxByType, + }, + inject: ['fullPath'], + data() { + return { + projects: [], + search: '', + selectedProject: {}, + shouldSkipQuery: true, + }; + }, + apollo: { + projects: { + query: searchProjectsQuery, + variables() { + return { + fullPath: this.fullPath, + search: this.search, + }; + }, + update: ({ group }) => group.projects.nodes ?? [], + error(error) { + createFlash({ + message: __('An error occurred while loading projects.'), + captureError: true, + error, + }); + }, + skip() { + return this.shouldSkipQuery; + }, + debounce: DEBOUNCE_DELAY, + }, + }, + computed: { + dropdownHref() { + return this.hasSelectedProject + ? joinPaths(this.selectedProject.webUrl, DASH_SCOPE, 'issues/new') + : undefined; + }, + dropdownText() { + return this.hasSelectedProject + ? sprintf(__('New issue in %{project}'), { project: this.selectedProject.name }) + : this.$options.i18n.defaultDropdownText; + }, + hasSelectedProject() { + return this.selectedProject.id; + }, + showNoSearchResultsText() { + return !this.projects.length && this.search; + }, + }, + methods: { + handleDropdownClick() { + if (!this.dropdownHref) { + this.$refs.dropdown.show(); + } + }, + handleDropdownShown() { + if (this.shouldSkipQuery) { + this.shouldSkipQuery = false; + } + this.$refs.search.focusInput(); + }, + selectProject(project) { + this.selectedProject = project; + }, + }, +}; +</script> + +<template> + <gl-dropdown + ref="dropdown" + right + split + :split-href="dropdownHref" + :text="dropdownText" + :toggle-text="$options.i18n.toggleButtonLabel" + variant="confirm" + @click="handleDropdownClick" + @shown="handleDropdownShown" + > + <gl-search-box-by-type ref="search" v-model.trim="search" /> + <gl-loading-icon v-if="$apollo.queries.projects.loading" /> + <template v-else> + <gl-dropdown-item + v-for="project of projects" + :key="project.id" + @click="selectProject(project)" + > + {{ project.nameWithNamespace }} + </gl-dropdown-item> + <gl-dropdown-text v-if="showNoSearchResultsText"> + {{ $options.i18n.noMatchesFound }} + </gl-dropdown-text> + </template> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/issues_list/index.js b/app/assets/javascripts/issues_list/index.js index e89e3e8e681..62180c7ffa4 100644 --- a/app/assets/javascripts/issues_list/index.js +++ b/app/assets/javascripts/issues_list/index.js @@ -121,6 +121,7 @@ export function mountIssuesListApp() { fullPath, groupEpicsPath, hasAnyIssues, + hasAnyProjects, hasBlockedIssuesFeature, hasIssuableHealthStatusFeature, hasIssueWeightsFeature, @@ -153,6 +154,7 @@ export function mountIssuesListApp() { fullPath, groupEpicsPath, hasAnyIssues: parseBoolean(hasAnyIssues), + hasAnyProjects: parseBoolean(hasAnyProjects), hasBlockedIssuesFeature: parseBoolean(hasBlockedIssuesFeature), hasIssuableHealthStatusFeature: parseBoolean(hasIssuableHealthStatusFeature), hasIssueWeightsFeature: parseBoolean(hasIssueWeightsFeature), diff --git a/app/assets/javascripts/issues_list/queries/search_projects.query.graphql b/app/assets/javascripts/issues_list/queries/search_projects.query.graphql new file mode 100644 index 00000000000..df1f330139a --- /dev/null +++ b/app/assets/javascripts/issues_list/queries/search_projects.query.graphql @@ -0,0 +1,12 @@ +query searchProjects($fullPath: ID!, $search: String) { + group(fullPath: $fullPath) { + projects(search: $search, includeSubgroups: true) { + nodes { + id + name + nameWithNamespace + webUrl + } + } + } +} |