diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 13:49:51 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-02-20 13:49:51 +0000 |
commit | 71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e (patch) | |
tree | 6a2d93ef3fb2d353bb7739e4b57e6541f51cdd71 /app/assets/javascripts/boards/components | |
parent | a7253423e3403b8c08f8a161e5937e1488f5f407 (diff) | |
download | gitlab-ce-71786ddc8e28fbd3cb3fcc4b3ff15e5962a1c82e.tar.gz |
Add latest changes from gitlab-org/gitlab@15-9-stable-eev15.9.0-rc42
Diffstat (limited to 'app/assets/javascripts/boards/components')
15 files changed, 257 insertions, 83 deletions
diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue index 970e3509d20..d41fc1e9300 100644 --- a/app/assets/javascripts/boards/components/board_app.vue +++ b/app/assets/javascripts/boards/components/board_app.vue @@ -11,7 +11,12 @@ export default { BoardSettingsSidebar, BoardTopBar, }, - inject: ['fullBoardId'], + inject: ['initialBoardId'], + data() { + return { + boardId: this.initialBoardId, + }; + }, computed: { ...mapGetters(['isSidebarOpen']), }, @@ -21,13 +26,18 @@ export default { destroyed() { window.removeEventListener('popstate', refreshCurrentPage); }, + methods: { + switchBoard(id) { + this.boardId = id; + }, + }, }; </script> <template> <div class="boards-app gl-relative" :class="{ 'is-compact': isSidebarOpen }"> - <board-top-bar /> - <board-content :board-id="fullBoardId" /> + <board-top-bar :board-id="boardId" @switchBoard="switchBoard" /> + <board-content :board-id="boardId" /> <board-settings-sidebar /> </div> </template> diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 0c64cbad5b1..3071c1f334e 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -9,7 +9,7 @@ export default { BoardCardInner, }, mixins: [Tracking.mixin()], - inject: ['disabled'], + inject: ['disabled', 'isApolloBoard'], props: { list: { type: Object, @@ -63,6 +63,15 @@ export default { colorClass() { return this.isColorful ? 'gl-pl-4 gl-border-l-solid gl-border-4' : ''; }, + formattedItem() { + return this.isApolloBoard + ? { + ...this.item, + assignees: this.item.assignees?.nodes || [], + labels: this.item.labels?.nodes || [], + } + : this.item; + }, }, methods: { ...mapActions(['toggleBoardItemMultiSelection', 'toggleBoardItem']), @@ -106,7 +115,7 @@ export default { > <board-card-inner :list="list" - :item="item" + :item="formattedItem" :update-filters="true" :index="index" :show-work-item-type-icon="showWorkItemTypeIcon" diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue index 77df111afc1..88f51c71e06 100644 --- a/app/assets/javascripts/boards/components/board_card_inner.vue +++ b/app/assets/javascripts/boards/components/board_card_inner.vue @@ -214,7 +214,9 @@ export default { <template> <div> <div class="gl-display-flex" dir="auto"> - <h4 class="board-card-title gl-mb-0 gl-mt-0 gl-mr-3 gl-font-base gl-overflow-break-word"> + <h4 + class="board-card-title gl-min-w-0 gl-mb-0 gl-mt-0 gl-mr-3 gl-font-base gl-overflow-break-word" + > <issuable-blocked-icon v-if="item.blocked" :item="item" 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 index 706b453e868..f58f7838576 100644 --- a/app/assets/javascripts/boards/components/board_card_move_to_position.vue +++ b/app/assets/javascripts/boards/components/board_card_move_to_position.vue @@ -1,19 +1,17 @@ <script> -import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { GlDisclosureDropdown } from '@gitlab/ui'; import { mapActions, mapState } from 'vuex'; -import { s__ } from '~/locale'; - import Tracking from '~/tracking'; +import { + BOARD_CARD_MOVE_TO_POSITIONS_OPTIONS, + BOARD_CARD_MOVE_TO_POSITIONS_START_OPTION, +} from '../constants'; export default { - i18n: { - moveToStartText: s__('Boards|Move to start of list'), - moveToEndText: s__('Boards|Move to end of list'), - }, + BOARD_CARD_MOVE_TO_POSITIONS_OPTIONS, name: 'BoardCardMoveToPosition', components: { - GlDropdown, - GlDropdownItem, + GlDisclosureDropdown, }, mixins: [Tracking.mixin()], props: { @@ -96,30 +94,30 @@ export default { allItemsLoadedInList: !this.listHasNextPage, }); }, + selectMoveAction({ text }) { + if (text === BOARD_CARD_MOVE_TO_POSITIONS_START_OPTION) { + this.moveToStart(); + } else { + this.moveToEnd(); + } + }, }, }; </script> <template> - <gl-dropdown + <gl-disclosure-dropdown ref="dropdown" :key="itemIdentifier" - 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" + class="move-to-position gl-display-block gl-mb-2 gl-ml-auto gl-mt-n3 gl-mr-n3 js-no-trigger" category="tertiary" + :items="$options.BOARD_CARD_MOVE_TO_POSITIONS_OPTIONS" + icon="ellipsis_v" :tabindex="index" + :toggle-text="s__('Boards|Move card')" + :text-sr-only="true" no-caret - @keydown.esc.native="$emit('hide')" - > - <div> - <gl-dropdown-item @click.stop="moveToStart"> - {{ $options.i18n.moveToStartText }} - </gl-dropdown-item> - <gl-dropdown-item @click.stop="moveToEnd"> - {{ $options.i18n.moveToEndText }} - </gl-dropdown-item> - </div> - </gl-dropdown> + data-testid="board-move-to-position" + @action="selectMoveAction" + /> </template> diff --git a/app/assets/javascripts/boards/components/board_column.vue b/app/assets/javascripts/boards/components/board_column.vue index b728b8dd22a..708e1539c6e 100644 --- a/app/assets/javascripts/boards/components/board_column.vue +++ b/app/assets/javascripts/boards/components/board_column.vue @@ -9,17 +9,17 @@ export default { BoardListHeader, BoardList, }, - inject: { - boardId: { - default: '', - }, - }, + inject: ['isApolloBoard'], props: { list: { type: Object, default: () => ({}), required: false, }, + boardId: { + type: String, + required: true, + }, }, computed: { ...mapState(['filterParams', 'highlightedLists']), @@ -28,7 +28,7 @@ export default { return this.highlightedLists.includes(this.list.id); }, listItems() { - return this.getBoardItemsByList(this.list.id); + return this.isApolloBoard ? [] : this.getBoardItemsByList(this.list.id); }, isListDraggable() { return isListDraggable(this.list); @@ -84,7 +84,13 @@ export default { :class="{ 'board-column-highlighted': highlighted }" > <board-list-header :list="list" /> - <board-list ref="board-list" :board-items="listItems" :list="list" /> + <board-list + ref="board-list" + :board-id="boardId" + :board-items="listItems" + :list="list" + :filter-params="filterParams" + /> </div> </div> </template> diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue index 92f79e61f14..8a37719eae8 100644 --- a/app/assets/javascripts/boards/components/board_content.vue +++ b/app/assets/javascripts/boards/components/board_content.vue @@ -116,6 +116,8 @@ export default { value: this.boardListsToUse, delay: 100, delayOnTouchOnly: true, + filter: 'input', + preventOnFilter: false, }; return this.canDragColumns ? options : {}; @@ -172,6 +174,7 @@ export default { v-for="(list, index) in boardListsToUse" :key="index" ref="board" + :board-id="boardId" :list="list" :data-draggable-item-type="$options.draggableItemTypes.list" :class="{ 'gl-xs-display-none!': addColumnFormVisible }" diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue index e6d1e558c37..6227f185eda 100644 --- a/app/assets/javascripts/boards/components/board_content_sidebar.vue +++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue @@ -6,12 +6,13 @@ import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdow import { __, sprintf } from '~/locale'; import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue'; import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue'; -import { BoardType, ISSUABLE, INCIDENT, issuableTypes } from '~/boards/constants'; +import { BoardType, ISSUABLE, INCIDENT } from '~/boards/constants'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; +import { TYPE_ISSUE } from '~/issues/constants'; import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue'; import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue'; import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_widget.vue'; -import SidebarSeverity from '~/sidebar/components/severity/sidebar_severity.vue'; +import SidebarSeverityWidget from '~/sidebar/components/severity/sidebar_severity_widget.vue'; import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue'; import SidebarTodoWidget from '~/sidebar/components/todo_toggle/sidebar_todo_widget.vue'; import SidebarLabelsWidget from '~/sidebar/components/labels/labels_select_widget/labels_select_root.vue'; @@ -30,7 +31,7 @@ export default { SidebarSubscriptionsWidget, SidebarDropdownWidget, SidebarTodoWidget, - SidebarSeverity, + SidebarSeverityWidget, MountingPortal, SidebarHealthStatusWidget: () => import('ee_component/sidebar/components/health_status/sidebar_health_status_widget.vue'), @@ -66,7 +67,7 @@ export default { default: false, }, issuableType: { - default: issuableTypes.issue, + default: TYPE_ISSUE, }, isGroupBoard: { default: false, @@ -174,7 +175,7 @@ export default { /> </template> <template #default> - <board-sidebar-title /> + <board-sidebar-title data-testid="sidebar-title" /> <sidebar-assignees-widget :iid="activeBoardItem.iid" :full-path="fullPath" @@ -237,7 +238,7 @@ export default { > {{ __('None') }} </sidebar-labels-widget> - <sidebar-severity + <sidebar-severity-widget v-if="isIncidentSidebar" :iid="activeBoardItem.iid" :project-path="fullPath" diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue index ce86a4d3123..1bc5d910561 100644 --- a/app/assets/javascripts/boards/components/board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/board_filtered_search.vue @@ -327,7 +327,6 @@ export default { if (Array.isArray(value)) { return value.map((valueItem) => encodeURIComponent(valueItem)); } - return encodeURIComponent(value); } diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 060a708a22f..6f2b35f5191 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -8,7 +8,13 @@ import { sortableStart, sortableEnd } from '~/sortable/utils'; import Tracking from '~/tracking'; import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql'; import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue'; -import { toggleFormEventPrefix, DraggableItemTypes } from '../constants'; +import { + DEFAULT_BOARD_LIST_ITEMS_SIZE, + toggleFormEventPrefix, + DraggableItemTypes, + listIssuablesQueries, + ListType, +} from 'ee_else_ce/boards/constants'; import eventHub from '../eventhub'; import BoardCard from './board_card.vue'; import BoardNewIssue from './board_new_issue.vue'; @@ -31,12 +37,24 @@ export default { BoardCardMoveToPosition, }, mixins: [Tracking.mixin()], - inject: ['isEpicBoard', 'disabled'], + inject: [ + 'isEpicBoard', + 'isGroupBoard', + 'disabled', + 'fullPath', + 'boardType', + 'issuableType', + 'isApolloBoard', + ], props: { list: { type: Object, required: true, }, + boardId: { + type: String, + required: true, + }, boardItems: { type: Array, required: true, @@ -48,6 +66,8 @@ export default { showCount: false, showIssueForm: false, showEpicForm: false, + currentList: null, + isLoadingMore: false, }; }, apollo: { @@ -66,15 +86,50 @@ export default { return this.isEpicBoard; }, }, + currentList: { + query() { + return listIssuablesQueries[this.issuableType].query; + }, + variables() { + return { + id: this.list.id, + ...this.listQueryVariables, + }; + }, + skip() { + return !this.isApolloBoard || this.list.collapsed; + }, + update(data) { + return data[this.boardType].board.lists.nodes[0]; + }, + context: { + isSingleRequest: true, + }, + }, }, computed: { ...mapState(['pageInfoByListId', 'listsFlags', 'filterParams', 'isUpdateIssueOrderInProgress']), + boardListItems() { + return this.isApolloBoard + ? this.currentList?.[`${this.issuableType}s`].nodes || [] + : this.boardItems; + }, + listQueryVariables() { + return { + fullPath: this.fullPath, + boardId: this.boardId, + filters: this.filterParams, + isGroup: this.isGroupBoard, + isProject: !this.isGroupBoard, + first: DEFAULT_BOARD_LIST_ITEMS_SIZE, + }; + }, listItemsCount() { return this.isEpicBoard ? this.list.epicsCount : this.boardList?.issuesCount; }, paginatedIssueText() { return sprintf(__('Showing %{pageSize} of %{total} %{issuableType}'), { - pageSize: this.boardItems.length, + pageSize: this.boardListItems.length, total: this.listItemsCount, issuableType: this.isEpicBoard ? 'epics' : 'issues', }); @@ -86,13 +141,17 @@ export default { return this.list.maxIssueCount > 0 && this.listItemsCount > this.list.maxIssueCount; }, hasNextPage() { - return this.pageInfoByListId[this.list.id]?.hasNextPage; + return this.isApolloBoard + ? this.currentList?.[`${this.issuableType}s`].pageInfo?.hasNextPage + : this.pageInfoByListId[this.list.id]?.hasNextPage; }, loading() { - return this.listsFlags[this.list.id]?.isLoading; + return this.isApolloBoard + ? this.$apollo.queries.currentList.loading && !this.isLoadingMore + : this.listsFlags[this.list.id]?.isLoading; }, loadingMore() { - return this.listsFlags[this.list.id]?.isLoadingMore; + return this.isApolloBoard ? this.isLoadingMore : this.listsFlags[this.list.id]?.isLoadingMore; }, epicCreateFormVisible() { return this.isEpicBoard && this.list.listType !== 'closed' && this.showEpicForm; @@ -105,7 +164,7 @@ export default { return this.canMoveIssue ? this.$refs.list.$el : this.$refs.list; }, showingAllItems() { - return this.boardItems.length === this.listItemsCount; + return this.boardListItems.length === this.listItemsCount; }, showingAllItemsText() { return this.isEpicBoard @@ -128,7 +187,7 @@ export default { tag: 'ul', 'ghost-class': 'board-card-drag-active', 'data-list-id': this.list.id, - value: this.boardItems, + value: this.boardListItems, delay: 100, delayOnTouchOnly: true, }; @@ -138,9 +197,12 @@ export default { disableScrollingWhenMutationInProgress() { return this.hasNextPage && this.isUpdateIssueOrderInProgress; }, + showMoveToPosition() { + return !this.disabled && this.list.listType !== ListType.closed; + }, }, watch: { - boardItems() { + boardListItems() { this.$nextTick(() => { this.showCount = this.scrollHeight() > Math.ceil(this.listHeight()); }); @@ -165,10 +227,10 @@ export default { methods: { ...mapActions(['fetchItemsForList', 'moveItem']), listHeight() { - return this.listRef.getBoundingClientRect().height; + return this.listRef?.getBoundingClientRect()?.height || 0; }, scrollHeight() { - return this.listRef.scrollHeight; + return this.listRef?.scrollHeight || 0; }, scrollTop() { return this.listRef.scrollTop + this.listHeight(); @@ -176,8 +238,20 @@ export default { scrollToTop() { this.listRef.scrollTop = 0; }, - loadNextPage() { - this.fetchItemsForList({ listId: this.list.id, fetchNext: true }); + async loadNextPage() { + if (this.isApolloBoard) { + this.isLoadingMore = true; + await this.$apollo.queries.currentList.fetchMore({ + variables: { + ...this.listQueryVariables, + id: this.list.id, + after: this.currentList?.[`${this.issuableType}s`].pageInfo.endCursor, + }, + }); + this.isLoadingMore = false; + } else { + this.fetchItemsForList({ listId: this.list.id, fetchNext: true }); + } }, toggleForm() { if (this.isEpicBoard) { @@ -292,7 +366,7 @@ export default { :data-board="list.id" :data-board-type="list.listType" :class="{ - 'bg-danger-100': boardItemsSizeExceedsMax, + 'gl-bg-red-100 gl-rounded-bottom-left-base gl-rounded-bottom-right-base': boardItemsSizeExceedsMax, 'gl-overflow-hidden': disableScrollingWhenMutationInProgress, 'gl-overflow-y-auto': !disableScrollingWhenMutationInProgress, }" @@ -303,7 +377,7 @@ export default { @end="handleDragOnEnd" > <board-card - v-for="(item, index) in boardItems" + v-for="(item, index) in boardListItems" ref="issue" :key="item.id" :index="index" @@ -312,13 +386,12 @@ export default { :data-draggable-item-type="$options.draggableItemTypes.card" :show-work-item-type-icon="!isEpicBoard" > - <!-- TODO: remove the condition when https://gitlab.com/gitlab-org/gitlab/-/issues/377862 is resolved --> <board-card-move-to-position - v-if="!isEpicBoard && !disabled" + v-if="showMoveToPosition" :item="item" :index="index" :list="list" - :list-items-length="boardItems.length" + :list-items-length="boardListItems.length" /> </board-card> <gl-intersection-observer @appear="onReachingListBottom"> diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue index 14dff8de70f..749fae0c426 100644 --- a/app/assets/javascripts/boards/components/board_list_header.vue +++ b/app/assets/javascripts/boards/components/board_list_header.vue @@ -125,7 +125,7 @@ export default { return this.list.collapsed ? this.$options.i18n.expand : this.$options.i18n.collapse; }, chevronIcon() { - return this.list.collapsed ? 'chevron-right' : 'chevron-down'; + return this.list.collapsed ? 'chevron-lg-right' : 'chevron-lg-down'; }, isNewIssueShown() { return (this.listType === ListType.backlog || this.showListHeaderButton) && !this.isEpicBoard; @@ -135,7 +135,9 @@ export default { }, isSettingsShown() { return ( - this.listType !== ListType.backlog && this.showListHeaderButton && !this.list.collapsed + this.listType !== ListType.backlog && + this.listType !== ListType.closed && + !this.list.collapsed ); }, uniqueKey() { @@ -321,6 +323,7 @@ export default { v-if="listType !== 'label'" v-gl-tooltip.hover :class="{ + 'gl-text-gray-500': list.collapsed, 'gl-display-block': list.collapsed || listType === 'milestone', }" :title="listTitle" @@ -376,7 +379,7 @@ export default { <!-- EE end --> <div - class="issue-count-badge gl-display-inline-flex gl-pr-2 no-drag gl-text-secondary" + class="gl-font-sm issue-count-badge gl-display-inline-flex gl-pr-2 no-drag gl-text-secondary" data-testid="issue-count-badge" :class="{ 'gl-display-none!': list.collapsed && isSwimlanesHeader, @@ -386,7 +389,7 @@ export default { <span class="gl-display-inline-flex" :class="{ 'gl-rotate-90': list.collapsed }"> <gl-tooltip :target="() => $refs.itemCount" :title="itemsTooltipLabel" /> <span ref="itemCount" class="gl-display-inline-flex gl-align-items-center"> - <gl-icon class="gl-mr-2" :name="countIcon" :size="16" /> + <gl-icon class="gl-mr-2" :name="countIcon" :size="14" /> <item-count v-if="!isLoading" :items-size="isEpicBoard ? list.epicsCount : boardList.issuesCount" @@ -397,7 +400,7 @@ export default { <template v-if="canShowTotalWeight"> <gl-tooltip :target="() => $refs.weightTooltip" :title="weightCountToolTip" /> <span ref="weightTooltip" class="gl-display-inline-flex gl-ml-3" data-testid="weight"> - <gl-icon class="gl-mr-2" name="weight" /> + <gl-icon class="gl-mr-2" name="weight" :size="14" /> {{ totalWeight }} </span> </template> @@ -413,6 +416,7 @@ export default { :aria-label="$options.i18n.newIssue" :title="$options.i18n.newIssue" class="no-drag" + size="small" icon="plus" @click="showNewIssueForm" /> @@ -424,6 +428,7 @@ export default { :aria-label="$options.i18n.newEpic" :title="$options.i18n.newEpic" class="no-drag" + size="small" icon="plus" @click="showNewEpicForm" /> @@ -434,6 +439,7 @@ export default { v-gl-tooltip.hover :aria-label="$options.i18n.listSettings" class="no-drag" + size="small" :title="$options.i18n.listSettings" icon="settings" @click="openSidebarSettings" diff --git a/app/assets/javascripts/boards/components/board_top_bar.vue b/app/assets/javascripts/boards/components/board_top_bar.vue index 368feba9a44..2e20ed70bb0 100644 --- a/app/assets/javascripts/boards/components/board_top_bar.vue +++ b/app/assets/javascripts/boards/components/board_top_bar.vue @@ -2,6 +2,7 @@ import BoardAddNewColumnTrigger from '~/boards/components/board_add_new_column_trigger.vue'; import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue'; import IssueBoardFilteredSearch from 'ee_else_ce/boards/components/issue_board_filtered_search.vue'; +import { getBoardQuery } from 'ee_else_ce/boards/boards_util'; import ConfigToggle from './config_toggle.vue'; import NewBoardButton from './new_board_button.vue'; import ToggleFocus from './toggle_focus.vue'; @@ -19,7 +20,46 @@ export default { EpicBoardFilteredSearch: () => import('ee_component/boards/components/epic_filtered_search.vue'), }, - inject: ['swimlanesFeatureAvailable', 'canAdminList', 'isSignedIn', 'isIssueBoard'], + inject: [ + 'swimlanesFeatureAvailable', + 'canAdminList', + 'isSignedIn', + 'isIssueBoard', + 'fullPath', + 'boardType', + 'isEpicBoard', + 'isApolloBoard', + ], + props: { + boardId: { + type: String, + required: true, + }, + }, + data() { + return { + board: {}, + }; + }, + apollo: { + board: { + query() { + return getBoardQuery(this.boardType, this.isEpicBoard); + }, + variables() { + return { + fullPath: this.fullPath, + boardId: this.boardId, + }; + }, + skip() { + return !this.isApolloBoard; + }, + update(data) { + return data.workspace.board; + }, + }, + }, }; </script> @@ -31,7 +71,7 @@ export default { <div class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-flex-grow-1 gl-lg-mb-0 gl-mb-3 gl-w-full" > - <boards-selector /> + <boards-selector :board-apollo="board" @switchBoard="$emit('switchBoard', $event)" /> <new-board-button /> <issue-board-filtered-search v-if="isIssueBoard" /> <epic-board-filtered-search v-else /> diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue index d26aeb69dd5..a1a49386b37 100644 --- a/app/assets/javascripts/boards/components/boards_selector.vue +++ b/app/assets/javascripts/boards/components/boards_selector.vue @@ -51,6 +51,7 @@ export default { 'weights', 'boardType', 'isGroupBoard', + 'isApolloBoard', ], props: { throttleDuration: { @@ -58,15 +59,20 @@ export default { default: 200, required: false, }, + boardApollo: { + type: Object, + required: false, + default: () => ({}), + }, }, data() { return { hasScrollFade: false, - loadingBoards: 0, - loadingRecentBoards: false, scrollFadeInitialized: false, boards: [], recentBoards: [], + loadingBoards: false, + loadingRecentBoards: false, throttledSetScrollFade: throttle(this.setScrollFade, this.throttleDuration), contentClientHeight: 0, maxPosition: 0, @@ -77,11 +83,14 @@ export default { computed: { ...mapState(['board', 'isBoardLoading']), + boardToUse() { + return this.isApolloBoard ? this.boardApollo : this.board; + }, parentType() { return this.boardType; }, loading() { - return this.loadingRecentBoards || Boolean(this.loadingBoards); + return this.loadingRecentBoards || this.loadingBoards; }, filteredBoards() { return this.boards.filter((board) => @@ -94,6 +103,9 @@ export default { showDelete() { return this.boards.length > 1; }, + showDropdown() { + return this.showCreate || this.hasMissingBoards; + }, scrollFadeClass() { return { 'fade-out': !this.hasScrollFade, @@ -116,7 +128,7 @@ export default { this.scrollFadeInitialized = false; this.$nextTick(this.setScrollFade); }, - board(newBoard) { + boardToUse(newBoard) { document.title = newBoard.name; }, }, @@ -159,8 +171,10 @@ export default { return { fullPath: this.fullPath }; }, query: this.boardQuery, - loadingKey: 'loadingBoards', update: (data) => this.boardUpdate(data, 'boards'), + watchLoading: (isLoading) => { + this.loadingBoards = isLoading; + }, }); this.loadRecentBoards(); @@ -171,8 +185,10 @@ export default { return { fullPath: this.fullPath }; }, query: this.recentBoardsQuery, - loadingKey: 'loadingRecentBoards', update: (data) => this.boardUpdate(data, 'recentIssueBoards'), + watchLoading: (isLoading) => { + this.loadingRecentBoards = isLoading; + }, }); }, isScrolledUp() { @@ -210,9 +226,14 @@ export default { boardType: this.boardType, }); }, + fullBoardId(boardId) { + return fullBoardId(boardId); + }, async switchBoard(boardId, e) { if (isMetaKey(e)) { window.open(`${this.boardBaseUrl}/${boardId}`, '_blank'); + } else if (this.isApolloBoard) { + this.$emit('switchBoard', this.fullBoardId(boardId)); } else { this.unsetActiveId(); this.fetchCurrentBoard(boardId); @@ -230,12 +251,13 @@ export default { <div class="boards-switcher gl-mr-3" data-testid="boards-selector"> <span class="boards-selector-wrapper"> <gl-dropdown + v-if="showDropdown" data-testid="boards-dropdown" data-qa-selector="boards_dropdown" toggle-class="dropdown-menu-toggle" menu-class="flex-column dropdown-extended-height" :loading="isBoardLoading" - :text="board.name" + :text="boardToUse.name" @show="loadBoards" > <p class="gl-dropdown-header-top" @mousedown.prevent> @@ -333,7 +355,7 @@ export default { :can-admin-board="canAdminBoard" :scoped-issue-board-feature-enabled="scopedIssueBoardFeatureEnabled" :weights="weights" - :current-board="board" + :current-board="boardToUse" :current-page="currentPage" @cancel="cancel" /> diff --git a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue index 38a171e8889..7749391ec6f 100644 --- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue @@ -7,7 +7,7 @@ import BoardFilteredSearch from 'ee_else_ce/boards/components/board_filtered_sea import axios from '~/lib/utils/axios_utils'; import { joinPaths } from '~/lib/utils/url_utility'; import issueBoardFilters from '~/boards/issue_board_filters'; -import { TYPE_USER } from '~/graphql_shared/constants'; +import { TYPENAME_USER } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { __ } from '~/locale'; import { @@ -181,7 +181,7 @@ export default { return gon?.current_user_id ? [ { - id: convertToGraphQLId(TYPE_USER, gon.current_user_id), + id: convertToGraphQLId(TYPENAME_USER, gon.current_user_id), name: gon.current_user_fullname, username: gon.current_username, avatarUrl: gon.current_user_avatar_url, diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue index b09b1d48ca5..c3f7c7d3ca2 100644 --- a/app/assets/javascripts/boards/components/issue_due_date.vue +++ b/app/assets/javascripts/boards/components/issue_due_date.vue @@ -102,7 +102,7 @@ export default { <gl-tooltip :target="() => $refs.issueDueDate" :placement="tooltipPlacement"> <span class="bold">{{ __('Due date') }}</span> <br /> - <span :class="{ 'text-danger-muted': isPastDue }">{{ title }}</span> + <span :class="{ 'gl-text-red-300': isPastDue }">{{ title }}</span> </gl-tooltip> </span> </template> diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue index 53e574e9942..43a2b13b81c 100644 --- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue @@ -1,5 +1,5 @@ <script> -import { GlAlert, GlButton, GlForm, GlFormGroup, GlFormInput } from '@gitlab/ui'; +import { GlAlert, GlButton, GlForm, GlFormGroup, GlFormInput, GlLink } from '@gitlab/ui'; import { mapGetters, mapActions } from 'vuex'; import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue'; import { joinPaths } from '~/lib/utils/url_utility'; @@ -13,6 +13,7 @@ export default { GlButton, GlFormGroup, GlFormInput, + GlLink, BoardEditableItem, }, directives: { @@ -130,7 +131,11 @@ export default { @off-click="handleOffClick" > <template #title> - <span data-testid="item-title">{{ item.title }}</span> + <span data-testid="item-title"> + <gl-link class="gl-reset-color gl-hover-text-blue-800" :href="item.webUrl"> + {{ item.title }} + </gl-link> + </span> </template> <template #collapsed> <span class="gl-text-gray-800">{{ item.referencePath }}</span> |