diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-05 18:08:05 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2024-01-05 18:08:05 +0300 |
commit | 4ba8ae97071935c39216afc53304c60386bbfa68 (patch) | |
tree | 452038ff8d19dcf69453dde0079b1db4870a3aae /app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget_with_edit.vue | |
parent | 7120254aee218529320c061696a2af530494e6aa (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget_with_edit.vue')
-rw-r--r-- | app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget_with_edit.vue | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget_with_edit.vue b/app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget_with_edit.vue new file mode 100644 index 00000000000..53149f62893 --- /dev/null +++ b/app/assets/javascripts/work_items/components/shared/work_item_sidebar_dropdown_widget_with_edit.vue @@ -0,0 +1,194 @@ +<script> +import { GlButton, GlForm, GlLoadingIcon, GlCollapsibleListbox } from '@gitlab/ui'; +import { isEmpty } from 'lodash'; + +import { s__, __ } from '~/locale'; + +export default { + i18n: { + none: s__('WorkItem|None'), + noMatchingResults: s__('WorkItem|No matching results'), + editButtonLabel: __('Edit'), + applyButtonLabel: __('Apply'), + resetButtonText: __('Clear'), + }, + components: { + GlButton, + GlLoadingIcon, + GlForm, + GlCollapsibleListbox, + }, + props: { + canUpdate: { + type: Boolean, + required: false, + default: false, + }, + dropdownLabel: { + type: String, + required: true, + }, + dropdownName: { + type: String, + required: true, + }, + listItems: { + type: Array, + required: false, + default: () => [], + }, + itemValue: { + type: Object, + required: false, + default: null, + }, + loading: { + type: Boolean, + required: false, + default: false, + }, + updateInProgress: { + type: Boolean, + required: false, + default: false, + }, + resetButtonLabel: { + type: String, + required: false, + default: '', + }, + headerText: { + type: String, + required: false, + default: '', + }, + toggleDropdownText: { + type: String, + required: false, + default: '', + }, + }, + data() { + return { + isEditing: false, + localSelectedItem: this.itemValue?.id, + }; + }, + computed: { + hasValue() { + return this.itemValue != null || !isEmpty(this.item); + }, + listboxText() { + return ( + this.listItems.find(({ value }) => this.localSelectedItem === value)?.text || + this.itemValue?.title || + this.$options.i18n.none + ); + }, + inputId() { + return `work-item-dropdown-listbox-value-${this.dropdownName}`; + }, + toggleText() { + return this.toggleDropdownText || this.listboxText; + }, + resetButton() { + return this.resetButtonLabel || this.$options.i18n.resetButtonText; + }, + }, + watch: { + itemValue: { + handler(newVal) { + if (!this.isEditing) { + this.localSelectedItem = newVal?.id; + } + }, + }, + }, + methods: { + setSearchKey(value) { + this.$emit('searchStarted', value); + }, + handleItemClick(item) { + this.localSelectedItem = item; + this.$emit('updateValue', item); + }, + onListboxShown() { + this.$emit('dropdownShown'); + }, + onListboxHide() { + this.isEditing = false; + }, + unassignValue() { + this.localSelectedItem = null; + this.isEditing = false; + this.$emit('updateValue', null); + }, + }, +}; +</script> + +<template> + <div> + <div class="gl-display-flex gl-align-items-center gl-gap-3"> + <!-- hide header when editing, since we then have a form label. Keep it reachable for screenreader nav --> + <h3 :class="{ 'gl-sr-only': isEditing }" class="gl-mb-0! gl-heading-scale-5"> + {{ dropdownLabel }} + </h3> + <gl-loading-icon v-if="updateInProgress" /> + <gl-button + v-if="canUpdate && !isEditing" + data-testid="edit-button" + category="tertiary" + size="small" + class="gl-ml-auto gl-mr-2" + :disabled="updateInProgress" + @click="isEditing = true" + >{{ $options.i18n.editButtonLabel }}</gl-button + > + </div> + <gl-form v-if="isEditing"> + <div class="gl-display-flex gl-justify-content-space-between gl-align-items-center"> + <label :for="inputId" class="gl-mb-0">{{ dropdownLabel }}</label> + <gl-button + data-testid="apply-button" + category="tertiary" + size="small" + class="gl-mr-2" + :disabled="updateInProgress" + @click="isEditing = false" + >{{ $options.i18n.applyButtonLabel }}</gl-button + > + </div> + <gl-collapsible-listbox + :id="inputId" + block + searchable + start-opened + is-check-centered + fluid-width + :searching="loading" + :header-text="headerText" + :toggle-text="toggleText" + :no-results-text="$options.i18n.noMatchingResults" + :items="listItems" + :selected="localSelectedItem" + :reset-button-label="resetButton" + @reset="unassignValue" + @search="setSearchKey" + @select="handleItemClick" + @shown="onListboxShown" + @hidden="onListboxHide" + > + <template #list-item="{ item }"> + <slot name="list-item" :item="item">{{ item.text }}</slot> + </template> + </gl-collapsible-listbox> + </gl-form> + <slot v-else-if="hasValue" name="readonly"> + {{ listboxText }} + </slot> + <div v-else class="gl-text-secondary"> + {{ $options.i18n.none }} + </div> + </div> +</template> |