diff options
Diffstat (limited to 'app/assets/javascripts/boards/components/board_list.vue')
-rw-r--r-- | app/assets/javascripts/boards/components/board_list.vue | 89 |
1 files changed, 51 insertions, 38 deletions
diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 94e29f3ad86..81740b5cd17 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -1,10 +1,11 @@ <script> -import { GlLoadingIcon } from '@gitlab/ui'; +import { GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui'; import Draggable from 'vuedraggable'; import { mapActions, mapGetters, mapState } from 'vuex'; import { sortableStart, sortableEnd } from '~/boards/mixins/sortable_default_options'; import { sprintf, __ } from '~/locale'; import defaultSortableConfig from '~/sortable/sortable_config'; +import Tracking from '~/tracking'; import eventHub from '../eventhub'; import BoardCard from './board_card.vue'; import BoardNewIssue from './board_new_issue.vue'; @@ -21,6 +22,13 @@ export default { BoardCard, BoardNewIssue, GlLoadingIcon, + GlIntersectionObserver, + }, + mixins: [Tracking.mixin()], + inject: { + canAdminList: { + default: false, + }, }, props: { disabled: { @@ -35,11 +43,6 @@ export default { type: Array, required: true, }, - canAdminList: { - type: Boolean, - required: false, - default: false, - }, }, data() { return { @@ -65,7 +68,7 @@ export default { return this.list.maxIssueCount > 0 && this.listItemsCount > this.list.maxIssueCount; }, hasNextPage() { - return this.pageInfoByListId[this.list.id].hasNextPage; + return this.pageInfoByListId[this.list.id]?.hasNextPage; }, loading() { return this.listsFlags[this.list.id]?.isLoading; @@ -86,7 +89,9 @@ export default { : this.$options.i18n.showingAllIssues; }, treeRootWrapper() { - return this.canAdminList ? Draggable : 'ul'; + return this.canAdminList && !this.listsFlags[this.list.id]?.addItemToListInProgress + ? Draggable + : 'ul'; }, treeRootOptions() { const options = { @@ -108,19 +113,21 @@ export default { this.showCount = this.scrollHeight() > Math.ceil(this.listHeight()); }); }, - }, - created() { - eventHub.$on(`toggle-issue-form-${this.list.id}`, this.toggleForm); - eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop); - }, - mounted() { - // Scroll event on list to load more - this.listRef.addEventListener('scroll', this.onScroll); + 'list.id': { + handler(id, oldVal) { + if (id) { + eventHub.$on(`toggle-issue-form-${this.list.id}`, this.toggleForm); + eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop); + eventHub.$off(`toggle-issue-form-${oldVal}`, this.toggleForm); + eventHub.$off(`scroll-board-list-${oldVal}`, this.scrollToTop); + } + }, + immediate: true, + }, }, beforeDestroy() { eventHub.$off(`toggle-issue-form-${this.list.id}`, this.toggleForm); eventHub.$off(`scroll-board-list-${this.list.id}`, this.scrollToTop); - this.listRef.removeEventListener('scroll', this.onScroll); }, methods: { ...mapActions(['fetchItemsForList', 'moveItem']), @@ -142,28 +149,31 @@ export default { toggleForm() { this.showIssueForm = !this.showIssueForm; }, - onScroll() { - window.requestAnimationFrame(() => { - if ( - !this.loadingMore && - this.scrollTop() > this.scrollHeight() - this.scrollOffset && - this.hasNextPage - ) { - this.loadNextPage(); - } - }); + onReachingListBottom() { + if (!this.loadingMore && this.hasNextPage) { + this.showCount = true; + this.loadNextPage(); + } }, handleDragOnStart() { sortableStart(); + this.track('drag_card', { label: 'board' }); }, handleDragOnEnd(params) { sortableEnd(); - const { newIndex, oldIndex, from, to, item } = params; + const { oldIndex, from, to, item } = params; + let { newIndex } = params; const { itemId, itemIid, itemPath } = item.dataset; - const { children } = to; + let { children } = to; let moveBeforeId; let moveAfterId; + children = Array.from(children).filter((card) => card.classList.contains('board-card')); + + if (newIndex > children.length) { + newIndex = children.length; + } + const getItemId = (el) => Number(el.dataset.itemId); // If item is being moved within the same list @@ -226,6 +236,7 @@ export default { :data-board="list.id" :data-board-type="list.listType" :class="{ 'bg-danger-100': boardItemsSizeExceedsMax }" + draggable=".board-card" class="board-list gl-w-full gl-h-full gl-list-style-none gl-mb-0 gl-p-2 js-board-list" data-testid="tree-root-wrapper" @start="handleDragOnStart" @@ -240,15 +251,17 @@ export default { :item="item" :disabled="disabled" /> - <li v-if="showCount" class="board-list-count gl-text-center" data-issue-id="-1"> - <gl-loading-icon - v-if="loadingMore" - :label="$options.i18n.loadingMoreboardItems" - data-testid="count-loading-icon" - /> - <span v-if="showingAllItems">{{ showingAllItemsText }}</span> - <span v-else>{{ paginatedIssueText }}</span> - </li> + <gl-intersection-observer @appear="onReachingListBottom"> + <li v-if="showCount" class="board-list-count gl-text-center" data-issue-id="-1"> + <gl-loading-icon + v-if="loadingMore" + :label="$options.i18n.loadingMoreboardItems" + data-testid="count-loading-icon" + /> + <span v-if="showingAllItems">{{ showingAllItemsText }}</span> + <span v-else>{{ paginatedIssueText }}</span> + </li> + </gl-intersection-observer> </component> </div> </template> |