diff options
Diffstat (limited to 'app/assets/javascripts/jira_connect')
6 files changed, 283 insertions, 0 deletions
diff --git a/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue b/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue new file mode 100644 index 00000000000..c1f57be7f97 --- /dev/null +++ b/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue @@ -0,0 +1,95 @@ +<script> +import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlLoadingIcon } from '@gitlab/ui'; +import { __ } from '~/locale'; +import { PROJECTS_PER_PAGE } from '../constants'; +import getProjectsQuery from '../graphql/queries/get_projects.query.graphql'; + +export default { + PROJECTS_PER_PAGE, + projectQueryPageInfo: { + endCursor: '', + }, + components: { + GlDropdown, + GlDropdownItem, + GlSearchBoxByType, + GlLoadingIcon, + }, + props: { + selectedProject: { + type: Object, + required: false, + default: null, + }, + }, + data() { + return { + initialProjectsLoading: true, + projectSearchQuery: '', + }; + }, + apollo: { + projects: { + query: getProjectsQuery, + variables() { + return { + search: this.projectSearchQuery, + first: this.$options.PROJECTS_PER_PAGE, + after: this.$options.projectQueryPageInfo.endCursor, + searchNamespaces: true, + sort: 'similarity', + }; + }, + update(data) { + return data?.projects?.nodes.filter((project) => !project.repository.empty) ?? []; + }, + result() { + this.initialProjectsLoading = false; + }, + error() { + this.onError({ message: __('Failed to load projects') }); + }, + }, + }, + computed: { + projectsLoading() { + return Boolean(this.$apollo.queries.projects.loading); + }, + projectDropdownText() { + return this.selectedProject?.nameWithNamespace || __('Select a project'); + }, + }, + methods: { + async onProjectSelect(project) { + this.$emit('change', project); + }, + onError({ message } = {}) { + this.$emit('error', { message }); + }, + isProjectSelected(project) { + return project.id === this.selectedProject?.id; + }, + }, +}; +</script> + +<template> + <gl-dropdown :text="projectDropdownText" :loading="initialProjectsLoading"> + <template #header> + <gl-search-box-by-type v-model.trim="projectSearchQuery" :debounce="250" /> + </template> + + <gl-loading-icon v-show="projectsLoading" /> + <template v-if="!projectsLoading"> + <gl-dropdown-item + v-for="project in projects" + :key="project.id" + is-check-item + :is-checked="isProjectSelected(project)" + @click="onProjectSelect(project)" + > + {{ project.nameWithNamespace }} + </gl-dropdown-item> + </template> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue b/app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue new file mode 100644 index 00000000000..0e2d8821f36 --- /dev/null +++ b/app/assets/javascripts/jira_connect/branches/components/source_branch_dropdown.vue @@ -0,0 +1,134 @@ +<script> +import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlLoadingIcon } from '@gitlab/ui'; +import { __ } from '~/locale'; +import { BRANCHES_PER_PAGE } from '../constants'; +import getProjectQuery from '../graphql/queries/get_project.query.graphql'; + +export default { + BRANCHES_PER_PAGE, + components: { + GlDropdown, + GlDropdownItem, + GlSearchBoxByType, + GlLoadingIcon, + }, + props: { + selectedProject: { + type: Object, + required: false, + default: null, + }, + selectedBranchName: { + type: String, + required: false, + default: null, + }, + }, + data() { + return { + sourceBranchSearchQuery: '', + initialSourceBranchNamesLoading: false, + sourceBranchNamesLoading: false, + sourceBranchNames: [], + }; + }, + computed: { + hasSelectedProject() { + return Boolean(this.selectedProject); + }, + hasSelectedSourceBranch() { + return Boolean(this.selectedBranchName); + }, + branchDropdownText() { + return this.selectedBranchName || __('Select a branch'); + }, + }, + watch: { + selectedProject: { + immediate: true, + async handler(selectedProject) { + if (!selectedProject) return; + + this.initialSourceBranchNamesLoading = true; + await this.fetchSourceBranchNames({ projectPath: selectedProject.fullPath }); + this.initialSourceBranchNamesLoading = false; + }, + }, + }, + methods: { + onSourceBranchSelect(branchName) { + this.$emit('change', branchName); + }, + onSourceBranchSearchQuery(branchSearchQuery) { + this.branchSearchQuery = branchSearchQuery; + this.fetchSourceBranchNames({ + projectPath: this.selectedProject.fullPath, + searchPattern: this.branchSearchQuery, + }); + }, + onError({ message } = {}) { + this.$emit('error', { message }); + }, + async fetchSourceBranchNames({ projectPath, searchPattern } = {}) { + this.sourceBranchNamesLoading = true; + try { + const { data } = await this.$apollo.query({ + query: getProjectQuery, + variables: { + projectPath, + branchNamesLimit: this.$options.BRANCHES_PER_PAGE, + branchNamesOffset: 0, + branchNamesSearchPattern: searchPattern ? `*${searchPattern}*` : '*', + }, + }); + + const { branchNames, rootRef } = data?.project.repository || {}; + this.sourceBranchNames = branchNames || []; + + // Use root ref as the default selection + if (rootRef && !this.hasSelectedSourceBranch) { + this.onSourceBranchSelect(rootRef); + } + } catch (err) { + this.onError({ + message: __('Something went wrong while fetching source branches.'), + }); + } finally { + this.sourceBranchNamesLoading = false; + } + }, + }, +}; +</script> + +<template> + <gl-dropdown + :text="branchDropdownText" + :loading="initialSourceBranchNamesLoading" + :disabled="!hasSelectedProject" + :class="{ 'gl-font-monospace': hasSelectedSourceBranch }" + > + <template #header> + <gl-search-box-by-type + :debounce="250" + :value="sourceBranchSearchQuery" + @input="onSourceBranchSearchQuery" + /> + </template> + + <gl-loading-icon v-show="sourceBranchNamesLoading" /> + <template v-if="!sourceBranchNamesLoading"> + <gl-dropdown-item + v-for="branchName in sourceBranchNames" + v-show="!sourceBranchNamesLoading" + :key="branchName" + :is-checked="branchName === selectedBranchName" + is-check-item + class="gl-font-monospace" + @click="onSourceBranchSelect(branchName)" + > + {{ branchName }} + </gl-dropdown-item> + </template> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/jira_connect/branches/constants.js b/app/assets/javascripts/jira_connect/branches/constants.js new file mode 100644 index 00000000000..987c8d356b4 --- /dev/null +++ b/app/assets/javascripts/jira_connect/branches/constants.js @@ -0,0 +1,2 @@ +export const BRANCHES_PER_PAGE = 20; +export const PROJECTS_PER_PAGE = 20; diff --git a/app/assets/javascripts/jira_connect/branches/graphql/queries/get_project.query.graphql b/app/assets/javascripts/jira_connect/branches/graphql/queries/get_project.query.graphql new file mode 100644 index 00000000000..f3428e816d7 --- /dev/null +++ b/app/assets/javascripts/jira_connect/branches/graphql/queries/get_project.query.graphql @@ -0,0 +1,17 @@ +query getProject( + $projectPath: ID! + $branchNamesLimit: Int! + $branchNamesOffset: Int! + $branchNamesSearchPattern: String! +) { + project(fullPath: $projectPath) { + repository { + branchNames( + limit: $branchNamesLimit + offset: $branchNamesOffset + searchPattern: $branchNamesSearchPattern + ) + rootRef + } + } +} diff --git a/app/assets/javascripts/jira_connect/branches/graphql/queries/get_projects.query.graphql b/app/assets/javascripts/jira_connect/branches/graphql/queries/get_projects.query.graphql new file mode 100644 index 00000000000..e768154e210 --- /dev/null +++ b/app/assets/javascripts/jira_connect/branches/graphql/queries/get_projects.query.graphql @@ -0,0 +1,34 @@ +#import "~/graphql_shared/fragments/pageInfo.fragment.graphql" + +query getProjects( + $search: String! + $after: String = "" + $first: Int! + $searchNamespaces: Boolean = false + $sort: String + $membership: Boolean = true +) { + projects( + search: $search + after: $after + first: $first + membership: $membership + searchNamespaces: $searchNamespaces + sort: $sort + ) { + nodes { + id + name + nameWithNamespace + fullPath + avatarUrl + path + repository { + empty + } + } + pageInfo { + ...PageInfo + } + } +} diff --git a/app/assets/javascripts/jira_connect/components/groups_list.vue b/app/assets/javascripts/jira_connect/components/groups_list.vue index d764f778a9d..55233bb6326 100644 --- a/app/assets/javascripts/jira_connect/components/groups_list.vue +++ b/app/assets/javascripts/jira_connect/components/groups_list.vue @@ -89,6 +89,7 @@ export default { debounce="500" :placeholder="__('Search by name')" :is-loading="isLoadingMore" + :value="searchTerm" @input="onGroupSearch" /> |