summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/admin/topics/components/topic_select.vue
blob: 8bf5be1afd136c8edee76107df411232beaaed18 (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
<script>
import {
  GlAvatarLabeled,
  GlDropdown,
  GlDropdownItem,
  GlDropdownText,
  GlSearchBoxByType,
} from '@gitlab/ui';
import { s__ } from '~/locale';
import { AVATAR_SHAPE_OPTION_RECT } from '~/vue_shared/constants';
import searchProjectTopics from '~/graphql_shared/queries/project_topics_search.query.graphql';

export default {
  components: {
    GlAvatarLabeled,
    GlDropdown,
    GlDropdownItem,
    GlDropdownText,
    GlSearchBoxByType,
  },
  props: {
    selectedTopic: {
      type: Object,
      required: false,
      default: () => ({}),
    },
    labelText: {
      type: String,
      required: false,
      default: null,
    },
  },
  apollo: {
    topics: {
      query: searchProjectTopics,
      variables() {
        return {
          search: this.search,
        };
      },
      update(data) {
        return data.topics?.nodes || [];
      },
      debounce: 250,
    },
  },
  data() {
    return {
      topics: [],
      search: '',
    };
  },
  computed: {
    loading() {
      return this.$apollo.queries.topics.loading;
    },
    isResultEmpty() {
      return this.topics.length === 0;
    },
    dropdownText() {
      if (Object.keys(this.selectedTopic).length) {
        return this.selectedTopic.name;
      }

      return this.$options.i18n.dropdownText;
    },
  },
  methods: {
    selectTopic(topic) {
      this.$emit('click', topic);
    },
  },
  i18n: {
    dropdownText: s__('TopicSelect|Select a topic'),
    searchPlaceholder: s__('TopicSelect|Search topics'),
    emptySearchResult: s__('TopicSelect|No matching results'),
  },
  AVATAR_SHAPE_OPTION_RECT,
};
</script>

<template>
  <div>
    <label v-if="labelText">{{ labelText }}</label>
    <gl-dropdown block :text="dropdownText">
      <gl-search-box-by-type
        v-model="search"
        :is-loading="loading"
        :placeholder="$options.i18n.searchPlaceholder"
      />
      <gl-dropdown-item v-for="topic in topics" :key="topic.id" @click="selectTopic(topic)">
        <gl-avatar-labeled
          :label="topic.title"
          :sub-label="topic.name"
          :src="topic.avatarUrl"
          :entity-name="topic.name"
          :size="32"
          :shape="$options.AVATAR_SHAPE_OPTION_RECT"
        />
      </gl-dropdown-item>
      <gl-dropdown-text v-if="isResultEmpty && !loading">
        <span class="gl-text-gray-500">{{ $options.i18n.emptySearchResult }}</span>
      </gl-dropdown-text>
    </gl-dropdown>
  </div>
</template>