145 lines
3.1 KiB
Vue
145 lines
3.1 KiB
Vue
<script>
|
|
import { GlCollapsibleListbox } from '@gitlab/ui';
|
|
import { debounce } from 'lodash';
|
|
import { createAlert } from '~/alert';
|
|
import { __ } from '~/locale';
|
|
import axios from '~/lib/utils/axios_utils';
|
|
|
|
export default {
|
|
components: {
|
|
GlCollapsibleListbox,
|
|
},
|
|
props: {
|
|
staticData: {
|
|
type: Array,
|
|
required: false,
|
|
default: () => [],
|
|
},
|
|
endpoint: {
|
|
type: String,
|
|
required: false,
|
|
default: '',
|
|
},
|
|
default: {
|
|
type: Object,
|
|
required: true,
|
|
},
|
|
dropdownHeader: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
isProject: {
|
|
type: Boolean,
|
|
required: false,
|
|
default: false,
|
|
},
|
|
inputId: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
inputName: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
toggleClass: {
|
|
type: String,
|
|
required: false,
|
|
default: '',
|
|
},
|
|
qaSelector: {
|
|
type: String,
|
|
required: false,
|
|
default: null,
|
|
},
|
|
},
|
|
data() {
|
|
return {
|
|
current: this.default,
|
|
selected: this.default.value,
|
|
isLoading: false,
|
|
data: this.staticData,
|
|
searchStr: '',
|
|
};
|
|
},
|
|
computed: {
|
|
filteredData() {
|
|
if (this.endpoint) return this.data;
|
|
|
|
return this.data.filter(
|
|
(d) => d.text.toLowerCase().indexOf(this.searchStr.toLowerCase()) >= 0,
|
|
);
|
|
},
|
|
},
|
|
methods: {
|
|
async fetchData() {
|
|
if (!this.endpoint) return;
|
|
|
|
this.isLoading = true;
|
|
|
|
try {
|
|
const { data } = await axios.get(this.endpoint, {
|
|
params: { search: this.searchStr },
|
|
});
|
|
|
|
if (this.isProject) {
|
|
this.data = data.map((p) => ({
|
|
value: `${p.id}`,
|
|
text: p.full_path.replace(/^\//, ''),
|
|
refsUrl: p.refs_url,
|
|
}));
|
|
} else {
|
|
this.data = data.Branches.map((d) => ({
|
|
value: d,
|
|
text: d,
|
|
}));
|
|
}
|
|
|
|
this.isLoading = false;
|
|
} catch {
|
|
createAlert({
|
|
message: __('Error fetching data. Please try again.'),
|
|
primaryButton: { text: __('Try again'), clickHandler: () => this.fetchData() },
|
|
});
|
|
}
|
|
},
|
|
searchData: debounce(function searchData(search) {
|
|
this.searchStr = search;
|
|
this.fetchData();
|
|
}, 500),
|
|
selectItem(id) {
|
|
this.current = this.data.find((d) => d.value === id);
|
|
|
|
this.$emit('selected', this.current);
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div>
|
|
<input
|
|
:id="inputId"
|
|
type="hidden"
|
|
:value="current.value"
|
|
:name="inputName"
|
|
data-testid="target-project-input"
|
|
/>
|
|
<gl-collapsible-listbox
|
|
v-model="selected"
|
|
:items="filteredData"
|
|
:toggle-text="current.text || dropdownHeader"
|
|
:header-text="dropdownHeader"
|
|
:searching="isLoading"
|
|
searchable
|
|
class="gl-w-full dropdown-target-project"
|
|
:toggle-class="[
|
|
'gl-align-items-flex-start! gl-justify-content-start! mr-compare-dropdown',
|
|
toggleClass,
|
|
]"
|
|
:data-qa-selector="qaSelector"
|
|
@shown="fetchData"
|
|
@search="searchData"
|
|
@select="selectItem"
|
|
/>
|
|
</div>
|
|
</template>
|