summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-08-02 12:09:59 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-08-02 12:09:59 +0000
commit3eec6c2511af2b10cd25be64dcd84c4a35a7bcdb (patch)
tree8af0733be4f7cb507353ed97ca8d6b4e9e374b7f /app/assets/javascripts/vue_shared
parent1930898566965dbc1bd779089ec9e58e17674268 (diff)
downloadgitlab-ce-3eec6c2511af2b10cd25be64dcd84c4a35a7bcdb.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/vue_shared')
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js27
-rw-r--r--app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue148
2 files changed, 175 insertions, 0 deletions
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js
new file mode 100644
index 00000000000..eeed5e9dc3a
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.stories.js
@@ -0,0 +1,27 @@
+/* eslint-disable @gitlab/require-i18n-strings */
+
+import { __ } from '~/locale';
+import DropdownWidget from './dropdown_widget.vue';
+
+export default {
+ component: DropdownWidget,
+ title: 'vue_shared/components/dropdown/dropdown_widget/dropdown_widget',
+};
+
+const Template = (args, { argTypes }) => ({
+ components: { DropdownWidget },
+ props: Object.keys(argTypes),
+ template: '<dropdown-widget v-bind="$props" v-on="$props" />',
+});
+
+export const Default = Template.bind({});
+Default.args = {
+ options: [
+ { id: 'gid://gitlab/Milestone/-1', title: __('Any Milestone') },
+ { id: 'gid://gitlab/Milestone/0', title: __('No Milestone') },
+ { id: 'gid://gitlab/Milestone/-2', title: __('Upcoming') },
+ { id: 'gid://gitlab/Milestone/-3', title: __('Started') },
+ ],
+ selectText: 'Select',
+ searchText: 'Search',
+};
diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
new file mode 100644
index 00000000000..857131e544e
--- /dev/null
+++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_widget/dropdown_widget.vue
@@ -0,0 +1,148 @@
+<script>
+import {
+ GlLoadingIcon,
+ GlDropdown,
+ GlDropdownForm,
+ GlDropdownDivider,
+ GlDropdownItem,
+ GlSearchBoxByType,
+} from '@gitlab/ui';
+import { __ } from '~/locale';
+
+export default {
+ components: {
+ GlLoadingIcon,
+ GlDropdown,
+ GlDropdownForm,
+ GlDropdownDivider,
+ GlDropdownItem,
+ GlSearchBoxByType,
+ },
+ props: {
+ selectText: {
+ type: String,
+ required: false,
+ default: __('Select'),
+ },
+ searchText: {
+ type: String,
+ required: false,
+ default: __('Search'),
+ },
+ presetOptions: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ options: {
+ type: Array,
+ required: false,
+ default: () => [],
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ selected: {
+ type: Object,
+ required: false,
+ default: () => {},
+ },
+ searchTerm: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ isSearchEmpty() {
+ return this.searchTerm === '' && !this.isLoading;
+ },
+ noOptionsFound() {
+ return !this.isSearchEmpty && this.options.length === 0;
+ },
+ },
+ methods: {
+ selectOption(option) {
+ this.$emit('set-option', option || null);
+ },
+ isSelected(option) {
+ return this.selected && this.selected.title === option.title;
+ },
+ showDropdown() {
+ this.$refs.dropdown.show();
+ },
+ setFocus() {
+ this.$refs.search.focusInput();
+ },
+ setSearchTerm(search) {
+ this.$emit('set-search', search);
+ },
+ },
+ i18n: {
+ noMatchingResults: __('No matching results'),
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown
+ ref="dropdown"
+ :text="selectText"
+ lazy
+ menu-class="gl-w-full!"
+ class="gl-w-full"
+ v-on="$listeners"
+ @shown="setFocus"
+ >
+ <template #header>
+ <gl-search-box-by-type
+ ref="search"
+ :value="searchTerm"
+ :placeholder="searchText"
+ class="js-dropdown-input-field"
+ @input="setSearchTerm"
+ />
+ </template>
+ <gl-dropdown-form class="gl-relative gl-min-h-7">
+ <gl-loading-icon
+ v-if="isLoading"
+ size="md"
+ class="gl-absolute gl-left-0 gl-top-0 gl-right-0"
+ />
+ <template v-else>
+ <template v-if="isSearchEmpty && presetOptions.length > 0">
+ <gl-dropdown-item
+ v-for="option in presetOptions"
+ :key="option.id"
+ :is-checked="isSelected(option)"
+ :is-check-centered="true"
+ :is-check-item="true"
+ @click="selectOption(option)"
+ >
+ {{ option.title }}
+ </gl-dropdown-item>
+ <gl-dropdown-divider />
+ </template>
+ <gl-dropdown-item
+ v-for="option in options"
+ :key="option.id"
+ :is-checked="isSelected(option)"
+ :is-check-centered="true"
+ :is-check-item="true"
+ data-testid="unselected-option"
+ @click="selectOption(option)"
+ >
+ {{ option.title }}
+ </gl-dropdown-item>
+ <gl-dropdown-item v-if="noOptionsFound" class="gl-pl-6!">
+ {{ $options.i18n.noMatchingResults }}
+ </gl-dropdown-item>
+ </template>
+ </gl-dropdown-form>
+ <template #footer>
+ <slot name="footer"></slot>
+ </template>
+ </gl-dropdown>
+</template>