diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 09:09:51 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-08-18 09:09:51 +0300 |
commit | ad3b511ba360c7fc09fe519396c6d15f09845d66 (patch) | |
tree | 349d48c43bd9c48fd1bc93028c21c0ac715e752d /app/assets/javascripts/boards | |
parent | f3f9b9fe66f234528706fbe0e70a0e529b5d8d08 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/boards')
5 files changed, 153 insertions, 3 deletions
diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 3638fdd2ca5..192bc4b5d25 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -98,6 +98,6 @@ export default { class="board-card gl-p-5 gl-rounded-base" @click="toggleIssue($event)" > - <board-card-inner :list="list" :item="item" :update-filters="true" /> + <board-card-inner :list="list" :item="item" :update-filters="true" :index="index" /> </li> </template> diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue index 8dc521317cd..a9a4912d9e9 100644 --- a/app/assets/javascripts/boards/components/board_card_inner.vue +++ b/app/assets/javascripts/boards/components/board_card_inner.vue @@ -15,6 +15,7 @@ import { updateHistory } from '~/lib/utils/url_utility'; import { sprintf, __, n__ } from '~/locale'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; +import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue'; import { ListType } from '../constants'; import eventHub from '../eventhub'; import BoardBlockedIcon from './board_blocked_icon.vue'; @@ -34,6 +35,7 @@ export default { IssueCardWeight: () => import('ee_component/boards/components/issue_card_weight.vue'), BoardBlockedIcon, GlSprintf, + BoardCardMoveToPosition, }, directives: { GlTooltip: GlTooltipDirective, @@ -55,6 +57,10 @@ export default { required: false, default: false, }, + index: { + type: Number, + required: true, + }, }, data() { return { @@ -202,7 +208,7 @@ export default { <template> <div> <div class="gl-display-flex" dir="auto"> - <h4 class="board-card-title gl-mb-0 gl-mt-0"> + <h4 class="board-card-title gl-mb-0 gl-mt-0 gl-mr-3"> <board-blocked-icon v-if="item.blocked" :item="item" @@ -235,6 +241,7 @@ export default { >{{ item.title }}</a > </h4> + <board-card-move-to-position :item="item" :list="list" :index="index" /> </div> <div v-if="showLabelFooter" class="board-card-labels gl-mt-2 gl-display-flex gl-flex-wrap"> <template v-for="label in orderedLabels"> diff --git a/app/assets/javascripts/boards/components/board_card_move_to_position.vue b/app/assets/javascripts/boards/components/board_card_move_to_position.vue new file mode 100644 index 00000000000..053dbb62b2e --- /dev/null +++ b/app/assets/javascripts/boards/components/board_card_move_to_position.vue @@ -0,0 +1,140 @@ +<script> +import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { mapActions, mapGetters } from 'vuex'; +import { s__ } from '~/locale'; +import { DEFAULT_BOARD_LIST_ITEMS_SIZE } from 'ee_else_ce/boards/constants'; + +import Tracking from '~/tracking'; + +export default { + i18n: { + moveToStartText: s__('Boards|Move to start of list'), + moveToEndText: s__('Boards|Move to end of list'), + }, + name: 'BoardCardMoveToPosition', + components: { + GlDropdown, + GlDropdownItem, + }, + mixins: [Tracking.mixin()], + props: { + item: { + type: Object, + required: true, + validator: (item) => ['id', 'iid', 'referencePath'].every((key) => item[key]), + }, + list: { + type: Object, + required: false, + default: () => ({}), + }, + index: { + type: Number, + required: true, + }, + }, + computed: { + ...mapGetters(['getBoardItemsByList']), + tracking() { + return { + category: 'boards:list', + label: 'move_to_position', + property: `type_card`, + }; + }, + listItems() { + return this.getBoardItemsByList(this.list.id); + }, + firstItemInListId() { + return this.listItems[0]?.id; + }, + lengthOfListItemsInBoard() { + return this.listItems?.length; + }, + lastItemInTheListId() { + return this.listItems[this.lengthOfListItemsInBoard - 1]?.id; + }, + itemIdentifier() { + return `${this.item.id}-${this.item.iid}-${this.index}`; + }, + showMoveToEndOfList() { + return this.lengthOfListItemsInBoard <= DEFAULT_BOARD_LIST_ITEMS_SIZE; + }, + isFirstItemInList() { + return this.index === 0; + }, + isLastItemInList() { + return this.index === this.lengthOfListItemsInBoard - 1; + }, + }, + methods: { + ...mapActions(['moveItem']), + moveToStart() { + this.track('click_toggle_button', { + label: 'move_to_start', + }); + /** in case it is the first in the list don't call any action/mutation * */ + if (this.isFirstItemInList) { + return; + } + const moveAfterId = this.firstItemInListId; + this.moveToPosition({ + moveAfterId, + }); + }, + moveToEnd() { + this.track('click_toggle_button', { + label: 'move_to_end', + }); + /** in case it is the last in the list don't call any action/mutation * */ + if (this.isLastItemInList) { + return; + } + const moveBeforeId = this.lastItemInTheListId; + this.moveToPosition({ + moveBeforeId, + }); + }, + moveToPosition({ moveAfterId, moveBeforeId }) { + this.moveItem({ + itemId: this.item.id, + itemIid: this.item.iid, + itemPath: this.item.referencePath, + fromListId: this.list.id, + toListId: this.list.id, + moveAfterId, + moveBeforeId, + }); + }, + }, +}; +</script> + +<template> + <gl-dropdown + ref="dropdown" + :key="itemIdentifier" + data-testid="move-card-dropdown" + icon="ellipsis_v" + :text="s__('Boards|Move card')" + :text-sr-only="true" + class="move-to-position gl-display-block gl-mb-2 gl-ml-2 gl-mt-n3 gl-mr-n3" + category="tertiary" + :tabindex="index" + no-caret + @keydown.esc.native="$emit('hide')" + > + <div> + <gl-dropdown-item data-testid="action-move-to-first" @click.stop="moveToStart"> + {{ $options.i18n.moveToStartText }} + </gl-dropdown-item> + <gl-dropdown-item + v-if="showMoveToEndOfList" + data-testid="action-move-to-end" + @click.stop="moveToEnd" + > + {{ $options.i18n.moveToEndText }} + </gl-dropdown-item> + </div> + </gl-dropdown> +</template> diff --git a/app/assets/javascripts/boards/constants.js b/app/assets/javascripts/boards/constants.js index 0f290f566ba..d745eed556f 100644 --- a/app/assets/javascripts/boards/constants.js +++ b/app/assets/javascripts/boards/constants.js @@ -146,3 +146,5 @@ export default { BoardType, ListType, }; + +export const DEFAULT_BOARD_LIST_ITEMS_SIZE = 10; diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index 791182af806..f84274104b2 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -15,6 +15,7 @@ import { FilterFields, ListTypeTitles, DraggableItemTypes, + DEFAULT_BOARD_LIST_ITEMS_SIZE, } from 'ee_else_ce/boards/constants'; import { formatIssueInput, @@ -429,7 +430,7 @@ export default { filters: filterParams, isGroup: boardType === BoardType.group, isProject: boardType === BoardType.project, - first: 10, + first: DEFAULT_BOARD_LIST_ITEMS_SIZE, after: fetchNext ? state.pageInfoByListId[listId].endCursor : undefined, }; |