diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-01-24 21:11:44 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-01-24 21:11:44 +0300 |
commit | fd247970cfe1e98276c780fbdcca026b7960e42a (patch) | |
tree | ab7963eb9b30fd73283c526cb6ae4ca1ef61c06f /app/assets/javascripts/vue_shared/components/entity_select | |
parent | df9890e9a702e2f12bbc8f022b916ca72820a292 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/entity_select')
4 files changed, 169 insertions, 9 deletions
diff --git a/app/assets/javascripts/vue_shared/components/entity_select/constants.js b/app/assets/javascripts/vue_shared/components/entity_select/constants.js index a48bba3be8c..0fb5a2d5534 100644 --- a/app/assets/javascripts/vue_shared/components/entity_select/constants.js +++ b/app/assets/javascripts/vue_shared/components/entity_select/constants.js @@ -1,8 +1,16 @@ -import { __ } from '~/locale'; +import { __, s__ } from '~/locale'; -export const TOGGLE_TEXT = __('Search for a group'); -export const HEADER_TEXT = __('Select a group'); export const RESET_LABEL = __('Reset'); +export const QUERY_TOO_SHORT_MESSAGE = __('Enter at least three characters to search.'); + +// Groups +export const GROUP_TOGGLE_TEXT = __('Search for a group'); +export const GROUP_HEADER_TEXT = __('Select a group'); export const FETCH_GROUPS_ERROR = __('Unable to fetch groups. Reload the page to try again.'); export const FETCH_GROUP_ERROR = __('Unable to fetch group. Reload the page to try again.'); -export const QUERY_TOO_SHORT_MESSAGE = __('Enter at least three characters to search.'); + +// Projects +export const PROJECT_TOGGLE_TEXT = s__('ProjectSelect|Search for project'); +export const PROJECT_HEADER_TEXT = s__('ProjectSelect|Select a project'); +export const FETCH_PROJECTS_ERROR = __('Unable to fetch projects. Reload the page to try again.'); +export const FETCH_PROJECT_ERROR = __('Unable to fetch project. Reload the page to try again.'); diff --git a/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue b/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue index a5fc438e932..ff137d764ee 100644 --- a/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue +++ b/app/assets/javascripts/vue_shared/components/entity_select/group_select.vue @@ -5,7 +5,12 @@ import axios from '~/lib/utils/axios_utils'; import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils'; import Api, { DEFAULT_PER_PAGE } from '~/api'; import { groupsPath } from './utils'; -import { TOGGLE_TEXT, HEADER_TEXT, FETCH_GROUPS_ERROR, FETCH_GROUP_ERROR } from './constants'; +import { + GROUP_TOGGLE_TEXT, + GROUP_HEADER_TEXT, + FETCH_GROUPS_ERROR, + FETCH_GROUP_ERROR, +} from './constants'; import EntitySelect from './entity_select.vue'; export default { @@ -58,7 +63,7 @@ export default { let groups = []; let totalPages = 0; try { - const { data, headers } = await axios.get( + const { data = [], headers } = await axios.get( Api.buildUrl(groupsPath(this.groupsFilter, this.parentGroupID)), { params: { @@ -68,7 +73,7 @@ export default { }, }, ); - groups = (data.length ? data : data.results || []).map((group) => ({ + groups = data.map((group) => ({ ...group, text: group.full_name, value: String(group.id), @@ -99,8 +104,8 @@ export default { }, }, i18n: { - toggleText: TOGGLE_TEXT, - selectGroup: HEADER_TEXT, + toggleText: GROUP_TOGGLE_TEXT, + selectGroup: GROUP_HEADER_TEXT, }, }; </script> diff --git a/app/assets/javascripts/vue_shared/components/entity_select/init_project_selects.js b/app/assets/javascripts/vue_shared/components/entity_select/init_project_selects.js new file mode 100644 index 00000000000..eee90b0f4f7 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/entity_select/init_project_selects.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import ProjectSelect from './project_select.vue'; + +const SELECTOR = '.js-vue-project-select'; + +export const initProjectSelects = () => { + if (process.env.NODE_ENV !== 'production' && document.querySelector(SELECTOR) === null) { + // eslint-disable-next-line no-console + console.warn(`Attempted to initialize ProjectSelect but '${SELECTOR}' not found in the page`); + } + + document.querySelectorAll(SELECTOR).forEach((el) => { + const { label, inputName, inputId, groupId, selected: initialSelection } = el.dataset; + const clearable = parseBoolean(el.dataset.clearable); + + return new Vue({ + el, + name: 'ProjectSelectRoot', + render(createElement) { + return createElement(ProjectSelect, { + props: { + label, + inputName, + inputId, + groupId, + initialSelection, + clearable, + }, + }); + }, + }); + }); +}; diff --git a/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue b/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue new file mode 100644 index 00000000000..c71fb713f1c --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue @@ -0,0 +1,113 @@ +<script> +import { GlAlert } from '@gitlab/ui'; +import * as Sentry from '@sentry/browser'; +import Api from '~/api'; +import { + PROJECT_TOGGLE_TEXT, + PROJECT_HEADER_TEXT, + FETCH_PROJECTS_ERROR, + FETCH_PROJECT_ERROR, +} from './constants'; +import EntitySelector from './entity_select.vue'; + +export default { + components: { + GlAlert, + EntitySelector, + }, + props: { + label: { + type: String, + required: true, + }, + inputName: { + type: String, + required: true, + }, + inputId: { + type: String, + required: true, + }, + groupId: { + type: String, + required: true, + }, + initialSelection: { + type: String, + required: false, + default: null, + }, + clearable: { + type: Boolean, + required: false, + default: false, + }, + }, + data() { + return { + errorMessage: '', + }; + }, + methods: { + async fetchProjects(searchString = '') { + let projects = []; + try { + const { data = [] } = await Api.groupProjects(this.groupId, searchString, { + with_shared: true, + include_subgroups: false, + order_by: 'similarity', + simple: true, + }); + projects = data.map((item) => ({ + text: item.name_with_namespace || item.name, + value: String(item.id), + })); + } catch (error) { + this.handleError({ message: FETCH_PROJECTS_ERROR, error }); + } + return { items: projects, totalPages: 1 }; + }, + async fetchProjectName(projectId) { + let projectName = ''; + try { + const { data: project } = await Api.project(projectId); + projectName = project.name_with_namespace; + } catch (error) { + this.handleError({ message: FETCH_PROJECT_ERROR, error }); + } + return projectName; + }, + handleError({ message, error }) { + Sentry.captureException(error); + this.errorMessage = message; + }, + dismissError() { + this.errorMessage = ''; + }, + }, + i18n: { + searchForProject: PROJECT_TOGGLE_TEXT, + selectProject: PROJECT_HEADER_TEXT, + }, +}; +</script> + +<template> + <entity-selector + :label="label" + :input-name="inputName" + :input-id="inputId" + :initial-selection="initialSelection" + :clearable="clearable" + :header-text="$options.i18n.selectProject" + :default-toggle-text="$options.i18n.searchForProject" + :fetch-items="fetchProjects" + :fetch-initial-selection-text="fetchProjectName" + > + <template #error> + <gl-alert v-if="errorMessage" class="gl-mb-3" variant="danger" @dismiss="dismissError">{{ + errorMessage + }}</gl-alert> + </template> + </entity-selector> +</template> |