diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-30 12:09:12 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-08-30 12:09:12 +0300 |
commit | 4ac9f1b8eaef29daa484b27a3113505cfa6a6dcb (patch) | |
tree | bda090fb8cf7c97765ee891bd58f7f9ee4271301 /app/assets/javascripts | |
parent | abbedc2027e64b11b03be4639411f1943b81f7ce (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
9 files changed, 96 insertions, 183 deletions
diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 1aaefcaa13b..abd13a30156 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -37,6 +37,7 @@ import initBroadcastNotifications from './broadcast_notification'; import { initTopNav } from './nav'; import 'ee_else_ce/main_ee'; +import 'jh_else_ce/main_jh'; applyGitLabUIConfig(); diff --git a/app/assets/javascripts/main_jh.js b/app/assets/javascripts/main_jh.js new file mode 100644 index 00000000000..13a6b8f3d3d --- /dev/null +++ b/app/assets/javascripts/main_jh.js @@ -0,0 +1 @@ +// This is an empty file to satisfy jh_else_ce import for the JH main entry point diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js index 031472a7d20..831f3987041 100644 --- a/app/assets/javascripts/sidebar/mount_sidebar.js +++ b/app/assets/javascripts/sidebar/mount_sidebar.js @@ -258,6 +258,7 @@ export function mountSidebarLabels() { allowScopedLabels: parseBoolean(el.dataset.allowScopedLabels), initiallySelectedLabels: JSON.parse(el.dataset.selectedLabels), variant: DropdownVariant.Sidebar, + canUpdate: parseBoolean(el.dataset.canEdit), }, render: (createElement) => createElement(SidebarLabels), }); diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue index 6694e349b6e..b5c3ffabae0 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents.vue @@ -60,7 +60,7 @@ export default { }, }, methods: { - ...mapActions(['toggleDropdownContentsCreateView', 'toggleDropdownContents']), + ...mapActions(['toggleDropdownContentsCreateView']), }, }; </script> @@ -83,7 +83,7 @@ export default { size="small" class="js-btn-back dropdown-header-button p-0" icon="arrow-left" - @click="toggleDropdownContentsCreateView" + @click.stop="toggleDropdownContentsCreateView" /> <span class="flex-grow-1">{{ dropdownTitle }}</span> <gl-button @@ -92,7 +92,7 @@ export default { size="small" class="dropdown-header-button gl-p-0!" icon="close" - @click="toggleDropdownContents" + @click="$emit('closeDropdown')" /> </div> <component @@ -103,7 +103,7 @@ export default { :footer-create-label-title="footerCreateLabelTitle" :footer-manage-label-title="footerManageLabelTitle" @hideCreateView="toggleDropdownContentsCreateView" - @closeDropdown="$emit('closeDropdown', $event)" + @setLabels="$emit('setLabels', $event)" @toggleDropdownContentsCreateView="toggleDropdownContentsCreateView" /> </div> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue index 4651e7a1576..2e31b386fdd 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_create_view.vue @@ -1,8 +1,10 @@ <script> import { GlTooltipDirective, GlButton, GlFormInput, GlLink, GlLoadingIcon } from '@gitlab/ui'; +import produce from 'immer'; import createFlash from '~/flash'; import { __ } from '~/locale'; import createLabelMutation from './graphql/create_label.mutation.graphql'; +import projectLabelsQuery from './graphql/project_labels.query.graphql'; const errorMessage = __('Error creating label.'); @@ -47,6 +49,25 @@ export default { handleColorClick(color) { this.selectedColor = this.getColorCode(color); }, + updateLabelsInCache(store, label) { + const sourceData = store.readQuery({ + query: projectLabelsQuery, + variables: { fullPath: this.projectPath, searchTerm: '' }, + }); + + const collator = new Intl.Collator('en'); + const data = produce(sourceData, (draftData) => { + const { nodes } = draftData.workspace.labels; + nodes.push(label); + nodes.sort((a, b) => collator.compare(a.title, b.title)); + }); + + store.writeQuery({ + query: projectLabelsQuery, + variables: { fullPath: this.projectPath, searchTerm: '' }, + data, + }); + }, async createLabel() { this.labelCreateInProgress = true; try { @@ -59,6 +80,14 @@ export default { color: this.selectedColor, projectPath: this.projectPath, }, + update: ( + store, + { + data: { + labelCreate: { label }, + }, + }, + ) => this.updateLabelsInCache(store, label), }); if (labelCreate.errors.length) { createFlash({ message: errorMessage }); diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue index ffa37424c2c..224dbd3e29b 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_contents_labels_view.vue @@ -112,7 +112,7 @@ export default { this.debouncedSearchKeyUpdate = debounce(this.setSearchKey, DEFAULT_DEBOUNCE_AND_THROTTLE_MS); }, beforeDestroy() { - this.$emit('closeDropdown', this.localSelectedLabels); + this.$emit('setLabels', this.localSelectedLabels); this.debouncedSearchKeyUpdate.cancel(); }, methods: { @@ -166,7 +166,7 @@ export default { this.updateSelectedLabels(this.visibleLabels[this.currentHighlightItem]); this.searchKey = ''; } else if (e.keyCode === ESC_KEY_CODE) { - this.$emit('closeDropdown', this.localSelectedLabels); + this.$emit('setLabels', this.localSelectedLabels); } if (e.keyCode !== ESC_KEY_CODE) { @@ -180,7 +180,7 @@ export default { handleLabelClick(label) { this.updateSelectedLabels(label); if (!this.allowMultiselect) { - this.$emit('closeDropdown', this.localSelectedLabels); + this.$emit('setLabels', this.localSelectedLabels); } }, setSearchKey(value) { @@ -240,7 +240,7 @@ export default { <gl-link class="gl-display-flex gl-flex-direction-row gl-w-full gl-overflow-break-word label-item" data-testid="create-label-button" - @click="$emit('toggleDropdownContentsCreateView')" + @click.stop="$emit('toggleDropdownContentsCreateView')" > {{ footerCreateLabelTitle }} </gl-link> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue deleted file mode 100644 index 46edfa1c42a..00000000000 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/dropdown_title.vue +++ /dev/null @@ -1,40 +0,0 @@ -<script> -import { GlButton, GlLoadingIcon } from '@gitlab/ui'; -import { mapState, mapActions } from 'vuex'; - -export default { - components: { - GlButton, - GlLoadingIcon, - }, - props: { - labelsSelectInProgress: { - type: Boolean, - required: true, - }, - }, - computed: { - ...mapState(['allowLabelEdit', 'labelsFetchInProgress']), - }, - methods: { - ...mapActions(['toggleDropdownContents']), - }, -}; -</script> - -<template> - <div class="title hide-collapsed gl-mb-3"> - {{ __('Labels') }} - <template v-if="allowLabelEdit"> - <gl-loading-icon v-show="labelsSelectInProgress" size="sm" inline /> - <gl-button - category="tertiary" - size="small" - class="float-right js-sidebar-dropdown-toggle gl-mr-n2" - data-qa-selector="labels_edit_button" - @click="toggleDropdownContents" - >{{ __('Edit') }}</gl-button - > - </template> - </div> -</template> diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql index 9aa4f5d165e..eb478645a03 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/graphql/create_label.mutation.graphql @@ -6,9 +6,7 @@ mutation createLabel($title: String!, $color: String, $projectPath: ID, $groupPa id color description - descriptionHtml title - textColor } errors } diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue index 0499dfe468f..efe524996b2 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue @@ -1,14 +1,12 @@ <script> -import $ from 'jquery'; import Vue from 'vue'; import Vuex, { mapState, mapActions, mapGetters } from 'vuex'; import { isInViewport } from '~/lib/utils/common_utils'; import { __ } from '~/locale'; - +import SidebarEditableItem from '~/sidebar/components/sidebar_editable_item.vue'; import { DropdownVariant } from './constants'; import DropdownButton from './dropdown_button.vue'; import DropdownContents from './dropdown_contents.vue'; -import DropdownTitle from './dropdown_title.vue'; import DropdownValue from './dropdown_value.vue'; import DropdownValueCollapsed from './dropdown_value_collapsed.vue'; import issueLabelsQuery from './graphql/issue_labels.query.graphql'; @@ -19,11 +17,11 @@ Vue.use(Vuex); export default { store: new Vuex.Store(labelsSelectModule()), components: { - DropdownTitle, DropdownValue, DropdownButton, DropdownContents, DropdownValueCollapsed, + SidebarEditableItem, }, inject: ['iid', 'projectPath'], props: { @@ -139,15 +137,12 @@ export default { }, }, computed: { - ...mapState(['showDropdownButton', 'showDropdownContents']), + ...mapState(['showDropdownContents']), ...mapGetters([ 'isDropdownVariantSidebar', 'isDropdownVariantStandalone', 'isDropdownVariantEmbedded', ]), - dropdownButtonVisible() { - return this.isDropdownVariantSidebar ? this.showDropdownButton : true; - }, }, watch: { selectedLabels(selectedLabels) { @@ -182,99 +177,20 @@ export default { footerCreateLabelTitle: this.footerCreateLabelTitle, footerManageLabelTitle: this.footerManageLabelTitle, }); - - this.$store.subscribeAction({ - after: this.handleVuexActionDispatch, - }); - - document.addEventListener('mousedown', this.handleDocumentMousedown); - document.addEventListener('click', this.handleDocumentClick); - }, - beforeDestroy() { - document.removeEventListener('mousedown', this.handleDocumentMousedown); - document.removeEventListener('click', this.handleDocumentClick); }, methods: { - ...mapActions(['setInitialState', 'toggleDropdownContents']), - /** - * This method stores a mousedown event's target. - * Required by the click listener because the click - * event itself has no reference to this element. - */ - handleDocumentMousedown({ target }) { - this.mousedownTarget = target; - }, - /** - * This method listens for document-wide click event - * and toggle dropdown if user clicks anywhere outside - * the dropdown while dropdown is visible. - */ - handleDocumentClick({ target }) { - // We also perform the toggle exception check for the - // last mousedown event's target to avoid hiding the - // box when the mousedown happened inside the box and - // only the mouseup did not. - if ( - this.showDropdownContents && - !this.preventDropdownToggleOnClick(target) && - !this.preventDropdownToggleOnClick(this.mousedownTarget) - ) { - this.toggleDropdownContents(); - } - }, - /** - * This method checks whether a given click target - * should prevent the dropdown from being toggled. - */ - preventDropdownToggleOnClick(target) { - // This approach of element detection is needed - // as the dropdown wrapper is not using `GlDropdown` as - // it will also require us to use `BDropdownForm` - // which is yet to be implemented in GitLab UI. - const hasExceptionClass = [ - 'js-dropdown-button', - 'js-btn-cancel-create', - 'js-sidebar-dropdown-toggle', - ].some( - (className) => - target?.classList.contains(className) || - target?.parentElement?.classList.contains(className), - ); - - const hasExceptionParent = ['.js-btn-back', '.js-labels-list'].some( - (className) => $(target).parents(className).length, - ); - - const isInDropdownButtonCollapsed = this.$refs.dropdownButtonCollapsed?.$el.contains(target); - - const isInDropdownContents = this.$refs.dropdownContents?.$el.contains(target); - - return ( - hasExceptionClass || - hasExceptionParent || - isInDropdownButtonCollapsed || - isInDropdownContents - ); - }, + ...mapActions(['setInitialState']), handleDropdownClose(labels) { - // Only emit label updates if there are any labels to update - // on UI. - if (this.showDropdownContents) { - this.toggleDropdownContents(); - } if (labels.length) this.$emit('updateSelectedLabels', labels); this.$emit('onDropdownClose'); }, + collapseDropdown() { + this.$refs.editable.collapse(); + }, handleCollapsedValueClick() { this.$emit('toggleCollapse'); }, - setContentIsOnViewport(showDropdownContents) { - if (!showDropdownContents) { - this.contentIsOnViewport = true; - - return; - } - + setContentIsOnViewport() { this.$nextTick(() => { if (this.$refs.dropdownContents) { this.contentIsOnViewport = isInViewport(this.$refs.dropdownContents.$el); @@ -299,48 +215,55 @@ export default { :labels="issueLabels" @onValueClick="handleCollapsedValueClick" /> - <dropdown-title - :allow-label-edit="allowLabelEdit" - :labels-select-in-progress="labelsSelectInProgress" - /> - <dropdown-value - :disable-labels="labelsSelectInProgress" - :selected-labels="issueLabels" - :allow-label-remove="allowLabelRemove" - :allow-scoped-labels="allowScopedLabels" - :labels-filter-base-path="labelsFilterBasePath" - :labels-filter-param="labelsFilterParam" - @onLabelRemove="$emit('onLabelRemove', $event)" + <sidebar-editable-item + ref="editable" + :title="__('Labels')" + :loading="labelsSelectInProgress" + @open="setContentIsOnViewport" + @close="contentIsOnViewport = true" > - <slot></slot> - </dropdown-value> - <dropdown-button v-show="dropdownButtonVisible" class="gl-mt-2" /> - <dropdown-contents - v-if="dropdownButtonVisible && showDropdownContents" - ref="dropdownContents" - :allow-multiselect="allowMultiselect" - :labels-list-title="labelsListTitle" - :footer-create-label-title="footerCreateLabelTitle" - :footer-manage-label-title="footerManageLabelTitle" - :render-on-top="!contentIsOnViewport" - :labels-create-title="labelsCreateTitle" - :selected-labels="selectedLabels" - @closeDropdown="handleDropdownClose" - /> - </template> - <template v-if="isDropdownVariantStandalone || isDropdownVariantEmbedded"> - <dropdown-button v-show="dropdownButtonVisible" /> - <dropdown-contents - v-if="dropdownButtonVisible && showDropdownContents" - ref="dropdownContents" - :allow-multiselect="allowMultiselect" - :labels-list-title="labelsListTitle" - :footer-create-label-title="footerCreateLabelTitle" - :footer-manage-label-title="footerManageLabelTitle" - :render-on-top="!contentIsOnViewport" - :selected-labels="selectedLabels" - @closeDropdown="handleDropdownClose" - /> + <template #collapsed> + <dropdown-value + :disable-labels="labelsSelectInProgress" + :selected-labels="issueLabels" + :allow-label-remove="allowLabelRemove" + :allow-scoped-labels="allowScopedLabels" + :labels-filter-base-path="labelsFilterBasePath" + :labels-filter-param="labelsFilterParam" + @onLabelRemove="$emit('onLabelRemove', $event)" + > + <slot></slot> + </dropdown-value> + </template> + <template #default="{ edit }"> + <dropdown-value + :disable-labels="labelsSelectInProgress" + :selected-labels="issueLabels" + :allow-label-remove="allowLabelRemove" + :allow-scoped-labels="allowScopedLabels" + :labels-filter-base-path="labelsFilterBasePath" + :labels-filter-param="labelsFilterParam" + class="gl-mb-2" + @onLabelRemove="$emit('onLabelRemove', $event)" + > + <slot></slot> + </dropdown-value> + <dropdown-button /> + <dropdown-contents + v-if="edit" + ref="dropdownContents" + :allow-multiselect="allowMultiselect" + :labels-list-title="labelsListTitle" + :footer-create-label-title="footerCreateLabelTitle" + :footer-manage-label-title="footerManageLabelTitle" + :render-on-top="!contentIsOnViewport" + :labels-create-title="labelsCreateTitle" + :selected-labels="selectedLabels" + @closeDropdown="collapseDropdown" + @setLabels="handleDropdownClose" + /> + </template> + </sidebar-editable-item> </template> </div> </template> |