summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/vue_shared/components/entity_select/project_select.vue')
-rw-r--r--app/assets/javascripts/vue_shared/components/entity_select/project_select.vue168
1 files changed, 168 insertions, 0 deletions
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..393991d746e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/entity_select/project_select.vue
@@ -0,0 +1,168 @@
+<script>
+import { GlAlert } from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
+import Api from '~/api';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+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,
+ },
+ directives: {
+ SafeHtml,
+ },
+ props: {
+ label: {
+ type: String,
+ required: true,
+ },
+ hasHtmlLabel: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ inputName: {
+ type: String,
+ required: true,
+ },
+ inputId: {
+ type: String,
+ required: true,
+ },
+ groupId: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ userId: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ includeSubgroups: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ membership: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ orderBy: {
+ type: String,
+ required: false,
+ default: 'similarity',
+ },
+ initialSelection: {
+ type: String,
+ required: false,
+ default: null,
+ },
+ },
+ data() {
+ return {
+ errorMessage: '',
+ };
+ },
+ methods: {
+ async fetchProjects(searchString = '') {
+ let projects = [];
+ try {
+ const { data = [] } = await (() => {
+ const commonParams = {
+ order_by: this.orderBy,
+ simple: true,
+ };
+
+ if (this.groupId) {
+ return Api.groupProjects(this.groupId, searchString, {
+ ...commonParams,
+ with_shared: true,
+ include_subgroups: this.includeSubgroups,
+ simple: true,
+ });
+ }
+ // Note: the whole userId handling supports a single project selector that is slated for
+ // removal. Once we have deleted app/views/clusters/clusters/_advanced_settings.html.haml,
+ // we should be able to clean this up.
+ if (this.userId) {
+ return Api.userProjects(
+ this.userId,
+ searchString,
+ {
+ with_shared: true,
+ include_subgroups: this.includeSubgroups,
+ },
+ (res) => ({ data: res }),
+ );
+ }
+ return Api.projects(searchString, {
+ ...commonParams,
+ membership: this.membership,
+ });
+ })();
+ 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"
+ :header-text="$options.i18n.selectProject"
+ :default-toggle-text="$options.i18n.searchForProject"
+ :fetch-items="fetchProjects"
+ :fetch-initial-selection-text="fetchProjectName"
+ clearable
+ >
+ <template v-if="hasHtmlLabel" #label>
+ <span v-safe-html="label"></span>
+ </template>
+ <template #error>
+ <gl-alert v-if="errorMessage" class="gl-mb-3" variant="danger" @dismiss="dismissError">{{
+ errorMessage
+ }}</gl-alert>
+ </template>
+ </entity-selector>
+</template>