summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/jira_connect/branches/components/project_dropdown.vue
blob: 88005cccd89d609bdf11174c547b692390fe02fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
<script>
import {
  GlDropdown,
  GlSearchBoxByType,
  GlLoadingIcon,
  GlDropdownItem,
  GlAvatarLabeled,
} 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,
    GlAvatarLabeled,
  },
  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 || this.$options.i18n.selectProjectText;
    },
  },
  methods: {
    onProjectSelect(project) {
      this.$emit('change', project);
    },
    onError({ message } = {}) {
      this.$emit('error', { message });
    },
    isProjectSelected(project) {
      return project.id === this.selectedProject?.id;
    },
  },
  i18n: {
    selectProjectText: __('Select a project'),
  },
};
</script>

<template>
  <gl-dropdown
    :text="projectDropdownText"
    :loading="initialProjectsLoading"
    menu-class="gl-w-auto!"
    :header-text="$options.i18n.selectProjectText"
  >
    <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-check-centered
        :is-checked="isProjectSelected(project)"
        :data-testid="`test-project-${project.id}`"
        @click="onProjectSelect(project)"
      >
        <gl-avatar-labeled
          class="gl-text-truncate"
          shape="rect"
          :size="32"
          :src="project.avatarUrl"
          :label="project.name"
          :entity-name="project.name"
          :sub-label="project.nameWithNamespace"
        />
      </gl-dropdown-item>
    </template>
  </gl-dropdown>
</template>