diff options
Diffstat (limited to 'app/assets/javascripts/boards/components/board_list_deprecated.vue')
-rw-r--r-- | app/assets/javascripts/boards/components/board_list_deprecated.vue | 459 |
1 files changed, 0 insertions, 459 deletions
diff --git a/app/assets/javascripts/boards/components/board_list_deprecated.vue b/app/assets/javascripts/boards/components/board_list_deprecated.vue deleted file mode 100644 index fabaf7a85f5..00000000000 --- a/app/assets/javascripts/boards/components/board_list_deprecated.vue +++ /dev/null @@ -1,459 +0,0 @@ -<script> -import { GlLoadingIcon } from '@gitlab/ui'; -import { Sortable, MultiDrag } from 'sortablejs'; -import createFlash from '~/flash'; -import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; -import { sprintf, __ } from '~/locale'; -import eventHub from '../eventhub'; -import { - getBoardSortableDefaultOptions, - sortableStart, - sortableEnd, -} from '../mixins/sortable_default_options'; -import boardsStore from '../stores/boards_store'; -import boardCard from './board_card_deprecated.vue'; -import boardNewIssue from './board_new_issue_deprecated.vue'; - -// This component is being replaced in favor of './board_list.vue' for GraphQL boards - -Sortable.mount(new MultiDrag()); - -export default { - name: 'BoardList', - components: { - boardCard, - boardNewIssue, - GlLoadingIcon, - }, - props: { - disabled: { - type: Boolean, - required: true, - }, - list: { - type: Object, - required: true, - }, - issues: { - type: Array, - required: true, - }, - }, - data() { - return { - scrollOffset: 250, - filters: boardsStore.state.filters, - showCount: false, - showIssueForm: false, - }; - }, - computed: { - paginatedIssueText() { - return sprintf(__('Showing %{pageSize} of %{total} issues'), { - pageSize: this.list.issues.length, - total: this.list.issuesSize, - }); - }, - issuesSizeExceedsMax() { - return this.list.maxIssueCount > 0 && this.list.issuesSize > this.list.maxIssueCount; - }, - loading() { - return this.list.loading; - }, - }, - watch: { - filters: { - handler() { - // eslint-disable-next-line vue/no-mutating-props - this.list.loadingMore = false; - this.$refs.list.scrollTop = 0; - }, - deep: true, - }, - issues() { - this.$nextTick(() => { - if ( - this.scrollHeight() <= this.listHeight() && - this.list.issuesSize > this.list.issues.length && - this.list.isExpanded - ) { - // eslint-disable-next-line vue/no-mutating-props - this.list.page += 1; - this.list.getIssues(false).catch(() => { - // TODO: handle request error - }); - } - - if (this.scrollHeight() > Math.ceil(this.listHeight())) { - this.showCount = true; - } else { - this.showCount = false; - } - }); - }, - 'list.id': { - handler(id) { - if (id) { - eventHub.$on(`toggle-issue-form-${this.list.id}`, this.toggleForm); - } - }, - }, - }, - created() { - eventHub.$on(`toggle-issue-form-${this.list.id}`, this.toggleForm); - eventHub.$on(`scroll-board-list-${this.list.id}`, this.scrollToTop); - }, - mounted() { - const multiSelectOpts = { - multiDrag: true, - selectedClass: 'js-multi-select', - animation: 500, - }; - - const options = getBoardSortableDefaultOptions({ - scroll: true, - disabled: this.disabled, - filter: '.board-list-count, .is-disabled', - dataIdAttr: 'data-issue-id', - removeCloneOnHide: false, - ...multiSelectOpts, - group: { - name: 'issues', - /** - * Dynamically determine between which containers - * items can be moved or copied as - * Assignee lists (EE feature) require this behavior - */ - pull: (to, from, dragEl, e) => { - // As per Sortable's docs, `to` should provide - // reference to exact sortable container on which - // we're trying to drag element, but either it is - // a library's bug or our markup structure is too complex - // that `to` never points to correct container - // See https://github.com/RubaXa/Sortable/issues/1037 - // - // So we use `e.target` which is always accurate about - // which element we're currently dragging our card upon - // So from there, we can get reference to actual container - // and thus the container type to enable Copy or Move - if (e.target) { - const containerEl = - e.target.closest('.js-board-list') || e.target.querySelector('.js-board-list'); - const toBoardType = containerEl.dataset.boardType; - const cloneActions = { - label: ['milestone', 'assignee', 'iteration'], - assignee: ['milestone', 'label', 'iteration'], - milestone: ['label', 'assignee', 'iteration'], - iteration: ['label', 'assignee', 'milestone'], - }; - - if (toBoardType) { - const fromBoardType = this.list.type; - // For each list we check if the destination list is - // a the list were we should clone the issue - const shouldClone = Object.entries(cloneActions).some( - (entry) => fromBoardType === entry[0] && entry[1].includes(toBoardType), - ); - - if (shouldClone) { - return 'clone'; - } - } - } - - return true; - }, - revertClone: true, - }, - onStart: (e) => { - const card = this.$refs.issue[e.oldIndex]; - - card.showDetail = false; - - const { list } = card; - - const issue = list.findIssue(Number(e.item.dataset.issueId)); - - boardsStore.startMoving(list, issue); - - this.$root.$emit(BV_HIDE_TOOLTIP); - - sortableStart(); - }, - onAdd: (e) => { - const { items = [], newIndicies = [] } = e; - if (items.length) { - // Not using e.newIndex here instead taking a min of all - // the newIndicies. Basically we have to find that during - // a drop what is the index we're going to start putting - // all the dropped elements from. - const newIndex = Math.min(...newIndicies.map((obj) => obj.index).filter((i) => i !== -1)); - const issues = items.map((item) => - boardsStore.moving.list.findIssue(Number(item.dataset.issueId)), - ); - - boardsStore.moveMultipleIssuesToList({ - listFrom: boardsStore.moving.list, - listTo: this.list, - issues, - newIndex, - }); - } else { - boardsStore.moveIssueToList( - boardsStore.moving.list, - this.list, - boardsStore.moving.issue, - e.newIndex, - ); - this.$nextTick(() => { - e.item.remove(); - }); - } - }, - onUpdate: (e) => { - const sortedArray = this.sortable.toArray().filter((id) => id !== '-1'); - - const { items = [], newIndicies = [], oldIndicies = [] } = e; - if (items.length) { - const newIndex = Math.min(...newIndicies.map((obj) => obj.index)); - const issues = items.map((item) => - boardsStore.moving.list.findIssue(Number(item.dataset.issueId)), - ); - boardsStore.moveMultipleIssuesInList({ - list: this.list, - issues, - oldIndicies: oldIndicies.map((obj) => obj.index), - newIndex, - idArray: sortedArray, - }); - e.items.forEach((el) => { - Sortable.utils.deselect(el); - }); - boardsStore.clearMultiSelect(); - return; - } - - boardsStore.moveIssueInList( - this.list, - boardsStore.moving.issue, - e.oldIndex, - e.newIndex, - sortedArray, - ); - }, - onEnd: (e) => { - const { items = [], clones = [], to } = e; - - // This is not a multi select operation - if (!items.length && !clones.length) { - sortableEnd(); - return; - } - - let toList; - if (to) { - const containerEl = to.closest('.js-board-list'); - toList = boardsStore.findList('id', Number(containerEl.dataset.board)); - } - - /** - * onEnd is called irrespective if the cards were moved in the - * same list or the other list. Don't remove items if it's same list. - */ - const isSameList = toList && toList.id === this.list.id; - if (toList && !isSameList && boardsStore.shouldRemoveIssue(this.list, toList)) { - const issues = items.map((item) => this.list.findIssue(Number(item.dataset.issueId))); - if ( - issues.filter(Boolean).length && - !boardsStore.issuesAreContiguous(this.list, issues) - ) { - const indexes = []; - const ids = this.list.issues.map((i) => i.id); - issues.forEach((issue) => { - const index = ids.indexOf(issue.id); - if (index > -1) { - indexes.push(index); - } - }); - - // Descending sort because splice would cause index discrepancy otherwise - const sortedIndexes = indexes.sort((a, b) => (a < b ? 1 : -1)); - - sortedIndexes.forEach((i) => { - /** - * **setTimeout and splice each element one-by-one in a loop - * is intended.** - * - * The problem here is all the indexes are in the list but are - * non-contiguous. Due to that, when we splice all the indexes, - * at once, Vue -- during a re-render -- is unable to find reference - * nodes and the entire app crashes. - * - * If the indexes are contiguous, this piece of code is not - * executed. If it is, this is a possible regression. Only when - * issue indexes are far apart, this logic should ever kick in. - */ - setTimeout(() => { - // eslint-disable-next-line vue/no-mutating-props - this.list.issues.splice(i, 1); - }, 0); - }); - } - } - - if (!toList) { - createFlash({ - message: __('Something went wrong while performing the action.'), - }); - } - - if (!isSameList) { - boardsStore.clearMultiSelect(); - - // Since Vue's list does not re-render the same keyed item, we'll - // remove `multi-select` class to express it's unselected - if (clones && clones.length) { - clones.forEach((el) => el.classList.remove('multi-select')); - } - - // Due to some bug which I am unable to figure out - // Sortable does not deselect some pending items from the - // source list. - // We'll just do it forcefully here. - Array.from(document.querySelectorAll('.js-multi-select') || []).forEach((item) => { - Sortable.utils.deselect(item); - }); - - /** - * SortableJS leaves all the moving items "as is" on the DOM. - * Vue picks up and rehydrates the DOM, but we need to explicity - * remove the "trash" items from the DOM. - * - * This is in parity to the logic on single item move from a list/in - * a list. For reference, look at the implementation of onAdd method. - */ - this.$nextTick(() => { - if (items && items.length) { - items.forEach((item) => { - item.remove(); - }); - } - }); - } - sortableEnd(); - }, - onMove(e) { - return !e.related.classList.contains('board-list-count'); - }, - onSelect(e) { - const { - item: { classList }, - } = e; - - if ( - classList && - classList.contains('js-multi-select') && - !classList.contains('multi-select') - ) { - Sortable.utils.deselect(e.item); - } - }, - onDeselect: (e) => { - const { - item: { dataset, classList }, - } = e; - - if ( - classList && - classList.contains('multi-select') && - !classList.contains('js-multi-select') - ) { - const issue = this.list.findIssue(Number(dataset.issueId)); - boardsStore.toggleMultiSelect(issue); - } - }, - }); - - this.sortable = Sortable.create(this.$refs.list, options); - - // Scroll event on list to load more - this.$refs.list.addEventListener('scroll', this.onScroll); - }, - beforeDestroy() { - eventHub.$off(`toggle-issue-form-${this.list.id}`, this.toggleForm); - eventHub.$off(`scroll-board-list-${this.list.id}`, this.scrollToTop); - this.$refs.list.removeEventListener('scroll', this.onScroll); - }, - methods: { - listHeight() { - return this.$refs.list.getBoundingClientRect().height; - }, - scrollHeight() { - return this.$refs.list.scrollHeight; - }, - scrollTop() { - return this.$refs.list.scrollTop + this.listHeight(); - }, - scrollToTop() { - this.$refs.list.scrollTop = 0; - }, - loadNextPage() { - const getIssues = this.list.nextPage(); - const loadingDone = () => { - // eslint-disable-next-line vue/no-mutating-props - this.list.loadingMore = false; - }; - - if (getIssues) { - // eslint-disable-next-line vue/no-mutating-props - this.list.loadingMore = true; - getIssues.then(loadingDone).catch(loadingDone); - } - }, - toggleForm() { - this.showIssueForm = !this.showIssueForm; - }, - onScroll() { - if (!this.list.loadingMore && this.scrollTop() > this.scrollHeight() - this.scrollOffset) { - this.loadNextPage(); - } - }, - }, -}; -</script> - -<template> - <div - :class="{ 'd-none': !list.isExpanded, 'd-flex flex-column': list.isExpanded }" - class="board-list-component position-relative h-100" - data-qa-selector="board_list_cards_area" - > - <div v-if="loading" class="board-list-loading text-center" :aria-label="__('Loading issues')"> - <gl-loading-icon size="sm" /> - </div> - <board-new-issue v-if="list.type !== 'closed' && showIssueForm" :list="list" /> - <ul - v-show="!loading" - ref="list" - :data-board="list.id" - :data-board-type="list.type" - :class="{ 'is-smaller': showIssueForm, 'bg-danger-100': issuesSizeExceedsMax }" - class="board-list w-100 h-100 list-unstyled mb-0 p-1 js-board-list" - > - <board-card - v-for="(issue, index) in issues" - ref="issue" - :key="issue.id" - :index="index" - :list="list" - :issue="issue" - :disabled="disabled" - /> - <li v-if="showCount" class="board-list-count text-center" data-issue-id="-1"> - <gl-loading-icon v-show="list.loadingMore" size="sm" label="Loading more issues" /> - <span v-if="list.issues.length === list.issuesSize">{{ __('Showing all issues') }}</span> - <span v-else>{{ paginatedIssueText }}</span> - </li> - </ul> - </div> -</template> |