diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-20 14:43:17 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-04-20 14:43:17 +0300 |
commit | dfc94207fec2d84314b1a5410cface22e8b369bd (patch) | |
tree | c54022f61ced104305889a64de080998a0dc773b /app/assets/javascripts/boards | |
parent | b874efeff674f6bf0355d5d242ecf81c6f7155df (diff) |
Add latest changes from gitlab-org/gitlab@15-11-stable-eev15.11.0-rc42
Diffstat (limited to 'app/assets/javascripts/boards')
17 files changed, 233 insertions, 79 deletions
diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue index 48dfcf81f1e..c7e6cb38d15 100644 --- a/app/assets/javascripts/boards/components/board_app.vue +++ b/app/assets/javascripts/boards/components/board_app.vue @@ -4,6 +4,7 @@ import { refreshCurrentPage, queryToObject } from '~/lib/utils/url_utility'; import BoardContent from '~/boards/components/board_content.vue'; import BoardSettingsSidebar from '~/boards/components/board_settings_sidebar.vue'; import BoardTopBar from '~/boards/components/board_top_bar.vue'; +import activeBoardItemQuery from 'ee_else_ce/boards/graphql/client/active_board_item.query.graphql'; export default { components: { @@ -11,7 +12,7 @@ export default { BoardSettingsSidebar, BoardTopBar, }, - inject: ['initialBoardId', 'initialFilterParams'], + inject: ['initialBoardId', 'initialFilterParams', 'isIssueBoard', 'isApolloBoard'], data() { return { boardId: this.initialBoardId, @@ -19,11 +20,31 @@ export default { isShowingEpicsSwimlanes: Boolean(queryToObject(window.location.search).group_by), }; }, + apollo: { + activeBoardItem: { + query: activeBoardItemQuery, + variables() { + return { + isIssue: this.isIssueBoard, + }; + }, + skip() { + return !this.isApolloBoard; + }, + }, + }, + computed: { ...mapGetters(['isSidebarOpen']), isSwimlanesOn() { return (gon?.licensed_features?.swimlanes && this.isShowingEpicsSwimlanes) ?? false; }, + isAnySidebarOpen() { + if (this.isApolloBoard) { + return this.activeBoardItem?.id; + } + return this.isSidebarOpen; + }, }, created() { window.addEventListener('popstate', refreshCurrentPage); @@ -45,7 +66,7 @@ export default { </script> <template> - <div class="boards-app gl-relative" :class="{ 'is-compact': isSidebarOpen }"> + <div class="boards-app gl-relative" :class="{ 'is-compact': isAnySidebarOpen }"> <board-top-bar :board-id="boardId" :is-swimlanes-on="isSwimlanesOn" diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 3071c1f334e..18495f285da 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -1,6 +1,8 @@ <script> import { mapActions, mapState } from 'vuex'; import Tracking from '~/tracking'; +import setActiveBoardItemMutation from 'ee_else_ce/boards/graphql/client/set_active_board_item.mutation.graphql'; +import activeBoardItemQuery from 'ee_else_ce/boards/graphql/client/active_board_item.query.graphql'; import BoardCardInner from './board_card_inner.vue'; export default { @@ -9,7 +11,7 @@ export default { BoardCardInner, }, mixins: [Tracking.mixin()], - inject: ['disabled', 'isApolloBoard'], + inject: ['disabled', 'isIssueBoard', 'isApolloBoard'], props: { list: { type: Object, @@ -37,14 +39,30 @@ export default { default: true, }, }, + apollo: { + activeBoardItem: { + query: activeBoardItemQuery, + variables() { + return { + isIssue: this.isIssueBoard, + }; + }, + skip() { + return !this.isApolloBoard; + }, + }, + }, computed: { ...mapState(['selectedBoardItems', 'activeId']), + activeItemId() { + return this.isApolloBoard ? this.activeBoardItem?.id : this.activeId; + }, isActive() { - return this.item.id === this.activeId; + return this.item.id === this.activeItemId; }, multiSelectVisible() { return ( - !this.activeId && + !this.activeItemId && this.selectedBoardItems.findIndex((boardItem) => boardItem.id === this.item.id) > -1 ); }, @@ -83,10 +101,23 @@ export default { if (isMultiSelect && gon?.features?.boardMultiSelect) { this.toggleBoardItemMultiSelection(this.item); } else { - this.toggleBoardItem({ boardItem: this.item }); + if (this.isApolloBoard) { + this.toggleItem(); + } else { + this.toggleBoardItem({ boardItem: this.item }); + } this.track('click_card', { label: 'right_sidebar' }); } }, + toggleItem() { + this.$apollo.mutate({ + mutation: setActiveBoardItemMutation, + variables: { + boardItem: this.item, + isIssue: this.isIssueBoard, + }, + }); + }, }, }; </script> diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue index 88f51c71e06..befd04c29ae 100644 --- a/app/assets/javascripts/boards/components/board_card_inner.vue +++ b/app/assets/javascripts/boards/components/board_card_inner.vue @@ -275,7 +275,7 @@ export default { <gl-loading-icon v-if="item.isLoading" size="lg" class="gl-mt-5" /> <span v-if="item.referencePath" - class="board-card-number gl-overflow-hidden gl-display-flex gl-mr-3 gl-mt-3 gl-text-secondary" + class="board-card-number gl-overflow-hidden gl-display-flex gl-mr-3 gl-mt-3 gl-font-sm gl-text-secondary" :class="{ 'gl-font-base': isEpicBoard }" > <work-item-type-icon diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue index 84a8781db1c..946f3712834 100644 --- a/app/assets/javascripts/boards/components/board_content.vue +++ b/app/assets/javascripts/boards/components/board_content.vue @@ -206,6 +206,7 @@ export default { <epics-swimlanes v-else-if="boardListsToUse.length" ref="swimlanes" + :board-id="boardId" :lists="boardListsToUse" :can-admin-list="canAdminList" :filters="filterParams" diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue index 675878683ab..1b97214ff8b 100644 --- a/app/assets/javascripts/boards/components/board_content_sidebar.vue +++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue @@ -3,10 +3,12 @@ import { GlDrawer } from '@gitlab/ui'; import { MountingPortal } from 'portal-vue'; import { mapState, mapActions, mapGetters } from 'vuex'; import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdown_widget.vue'; +import activeBoardItemQuery from 'ee_else_ce/boards/graphql/client/active_board_item.query.graphql'; +import setActiveBoardItemMutation from 'ee_else_ce/boards/graphql/client/set_active_board_item.mutation.graphql'; 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 { ISSUABLE, INCIDENT } from '~/boards/constants'; +import { INCIDENT } from '~/boards/constants'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { TYPE_ISSUE, WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants'; import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue'; @@ -16,7 +18,6 @@ import SidebarSeverityWidget from '~/sidebar/components/severity/sidebar_severit 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'; -import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { components: { @@ -39,7 +40,6 @@ export default { SidebarWeightWidget: () => import('ee_component/sidebar/components/weight/sidebar_weight_widget.vue'), }, - mixins: [glFeatureFlagMixin()], inject: { multipleAssigneesFeatureAvailable: { default: false, @@ -71,31 +71,46 @@ export default { isGroupBoard: { default: false, }, + isApolloBoard: { + default: false, + }, }, inheritAttrs: false, + apollo: { + activeBoardCard: { + query: activeBoardItemQuery, + variables: { + isIssue: true, + }, + update(data) { + if (!data.activeBoardItem?.id) { + return { id: '', iid: '' }; + } + return { + ...data.activeBoardItem, + assignees: data.activeBoardItem.assignees?.nodes || [], + }; + }, + skip() { + return !this.isApolloBoard; + }, + }, + }, computed: { - ...mapGetters([ - 'isSidebarOpen', - 'activeBoardItem', - 'groupPathForActiveIssue', - 'projectPathForActiveIssue', - ]), + ...mapGetters(['activeBoardItem']), ...mapState(['sidebarType']), - isIssuableSidebar() { - return this.sidebarType === ISSUABLE; + activeBoardIssuable() { + return this.isApolloBoard ? this.activeBoardCard : this.activeBoardItem; }, - isIncidentSidebar() { - return this.activeBoardItem.type === INCIDENT; + isSidebarOpen() { + return Boolean(this.activeBoardIssuable?.id); }, - showSidebar() { - return this.isIssuableSidebar && this.isSidebarOpen; + isIncidentSidebar() { + return this.activeBoardIssuable?.type === INCIDENT; }, sidebarTitle() { return this.isIncidentSidebar ? __('Incident details') : __('Issue details'); }, - fullPath() { - return this.activeBoardItem?.referencePath?.split('#')[0] || ''; - }, parentType() { return this.isGroupBoard ? WORKSPACE_GROUP : WORKSPACE_PROJECT; }, @@ -120,6 +135,14 @@ export default { ? this.labelsFilterBasePath.replace(':project_path', this.projectPathForActiveIssue) : this.labelsFilterBasePath; }, + groupPathForActiveIssue() { + const { referencePath = '' } = this.activeBoardIssuable; + return referencePath.slice(0, referencePath.lastIndexOf('/')); + }, + projectPathForActiveIssue() { + const { referencePath = '' } = this.activeBoardIssuable; + return referencePath.slice(0, referencePath.indexOf('#')); + }, }, methods: { ...mapActions([ @@ -131,7 +154,19 @@ export default { 'setActiveItemHealthStatus', ]), handleClose() { - this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType }); + if (this.isApolloBoard) { + this.$apollo.mutate({ + mutation: setActiveBoardItemMutation, + variables: { + boardItem: null, + }, + }); + } else { + this.toggleBoardItem({ + boardItem: this.activeBoardIssuable, + sidebarType: this.sidebarType, + }); + } }, handleUpdateSelectedLabels({ labels, id }) { this.setActiveBoardItemLabels({ @@ -143,7 +178,7 @@ export default { }, handleLabelRemove(removeLabelId) { this.setActiveBoardItemLabels({ - iid: this.activeBoardItem.iid, + iid: this.activeBoardIssuable.iid, projectPath: this.projectPathForActiveIssue, removeLabelIds: [removeLabelId], }); @@ -156,7 +191,7 @@ export default { <mounting-portal mount-to="#js-right-sidebar-portal" name="board-content-sidebar" append> <gl-drawer v-bind="$attrs" - :open="showSidebar" + :open="isSidebarOpen" class="boards-sidebar" variant="sidebar" @close="handleClose" @@ -167,25 +202,27 @@ export default { <template #header> <sidebar-todo-widget class="gl-mt-3" - :issuable-id="activeBoardItem.id" - :issuable-iid="activeBoardItem.iid" - :full-path="fullPath" + :issuable-id="activeBoardIssuable.id" + :issuable-iid="activeBoardIssuable.iid" + :full-path="projectPathForActiveIssue" :issuable-type="issuableType" /> </template> <template #default> - <board-sidebar-title data-testid="sidebar-title" /> + <board-sidebar-title :active-item="activeBoardIssuable" data-testid="sidebar-title" /> <sidebar-assignees-widget - :iid="activeBoardItem.iid" - :full-path="fullPath" - :initial-assignees="activeBoardItem.assignees" + v-if="activeBoardItem.assignees" + :iid="activeBoardIssuable.iid" + :full-path="projectPathForActiveIssue" + :initial-assignees="activeBoardIssuable.assignees" :allow-multiple-assignees="multipleAssigneesFeatureAvailable" :editable="canUpdate" - @assignees-updated="setAssignees" + @assignees-updated="!isApolloBoard && setAssignees($event)" /> <sidebar-dropdown-widget v-if="epicFeatureAvailable && !isIncidentSidebar" - :iid="activeBoardItem.iid" + :key="`epic-${activeBoardItem.iid}`" + :iid="activeBoardIssuable.iid" issuable-attribute="epic" :workspace-path="projectPathForActiveIssue" :attr-workspace-path="groupPathForActiveIssue" @@ -194,7 +231,8 @@ export default { /> <div> <sidebar-dropdown-widget - :iid="activeBoardItem.iid" + :key="`milestone-${activeBoardItem.iid}`" + :iid="activeBoardIssuable.iid" issuable-attribute="milestone" :workspace-path="projectPathForActiveIssue" :attr-workspace-path="projectPathForActiveIssue" @@ -203,7 +241,8 @@ export default { /> <sidebar-iteration-widget v-if="iterationFeatureAvailable && !isIncidentSidebar" - :iid="activeBoardItem.iid" + :key="`iteration-${activeBoardItem.iid}`" + :iid="activeBoardIssuable.iid" :workspace-path="projectPathForActiveIssue" :attr-workspace-path="groupPathForActiveIssue" :issuable-type="issuableType" @@ -213,14 +252,14 @@ export default { </div> <board-sidebar-time-tracker /> <sidebar-date-widget - :iid="activeBoardItem.iid" - :full-path="fullPath" + :iid="activeBoardIssuable.iid" + :full-path="projectPathForActiveIssue" :issuable-type="issuableType" data-testid="sidebar-due-date" /> <sidebar-labels-widget class="block labels" - :iid="activeBoardItem.iid" + :iid="activeBoardIssuable.iid" :full-path="projectPathForActiveIssue" :allow-label-remove="allowLabelEdit" :allow-multiselect="true" @@ -232,40 +271,40 @@ export default { workspace-type="project" :issuable-type="issuableType" :label-create-type="labelType" - @onLabelRemove="handleLabelRemove" - @updateSelectedLabels="handleUpdateSelectedLabels" + @onLabelRemove="!isApolloBoard && handleLabelRemove($event)" + @updateSelectedLabels="!isApolloBoard && handleUpdateSelectedLabels($event)" > {{ __('None') }} </sidebar-labels-widget> <sidebar-severity-widget v-if="isIncidentSidebar" - :iid="activeBoardItem.iid" - :project-path="fullPath" - :initial-severity="activeBoardItem.severity" + :iid="activeBoardIssuable.iid" + :project-path="projectPathForActiveIssue" + :initial-severity="activeBoardIssuable.severity" /> <sidebar-weight-widget v-if="weightFeatureAvailable && !isIncidentSidebar" - :iid="activeBoardItem.iid" - :full-path="fullPath" + :iid="activeBoardIssuable.iid" + :full-path="projectPathForActiveIssue" :issuable-type="issuableType" - @weightUpdated="setActiveItemWeight($event)" + @weightUpdated="!isApolloBoard && setActiveItemWeight($event)" /> <sidebar-health-status-widget v-if="healthStatusFeatureAvailable" - :iid="activeBoardItem.iid" - :full-path="fullPath" + :iid="activeBoardIssuable.iid" + :full-path="projectPathForActiveIssue" :issuable-type="issuableType" - @statusUpdated="setActiveItemHealthStatus($event)" + @statusUpdated="!isApolloBoard && setActiveItemHealthStatus($event)" /> <sidebar-confidentiality-widget - :iid="activeBoardItem.iid" - :full-path="fullPath" + :iid="activeBoardIssuable.iid" + :full-path="projectPathForActiveIssue" :issuable-type="issuableType" - @confidentialityUpdated="setActiveItemConfidential($event)" + @confidentialityUpdated="!isApolloBoard && setActiveItemConfidential($event)" /> <sidebar-subscriptions-widget - :iid="activeBoardItem.iid" - :full-path="fullPath" + :iid="activeBoardIssuable.iid" + :full-path="projectPathForActiveIssue" :issuable-type="issuableType" data-testid="sidebar-notifications" /> diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue index 2e14afad963..46612320136 100644 --- a/app/assets/javascripts/boards/components/board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/board_filtered_search.vue @@ -22,7 +22,7 @@ import { TOKEN_TYPE_WEIGHT, } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; -import { AssigneeFilterType } from '~/boards/constants'; +import { AssigneeFilterType, GroupByParamType } from 'ee_else_ce/boards/constants'; import { TYPENAME_ITERATION } from '~/graphql_shared/constants'; import eventHub from '../eventhub'; @@ -33,6 +33,11 @@ export default { components: { FilteredSearch }, inject: ['initialFilterParams', 'isApolloBoard'], props: { + isSwimlanesOn: { + type: Boolean, + required: false, + default: false, + }, tokens: { type: Array, required: true, @@ -321,6 +326,7 @@ export default { release_tag: releaseTag, confidential, health_status: healthStatus, + group_by: this.isSwimlanesOn ? GroupByParamType.epic : undefined, }, (value) => { if (value || value === false) { diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue index 9ea801dc9a2..604e71f5993 100644 --- a/app/assets/javascripts/boards/components/board_form.vue +++ b/app/assets/javascripts/boards/components/board_form.vue @@ -226,12 +226,10 @@ export default { } this.cancel(); - if (!this.isApolloBoard) { - const param = getParameterByName('group_by') - ? `?group_by=${getParameterByName('group_by')}` - : ''; - updateHistory({ url: `${this.boardBaseUrl}/${getIdFromGraphQLId(board.id)}${param}` }); - } + const param = getParameterByName('group_by') + ? `?group_by=${getParameterByName('group_by')}` + : ''; + updateHistory({ url: `${this.boardBaseUrl}/${getIdFromGraphQLId(board.id)}${param}` }); } catch { this.setError({ message: this.$options.i18n.saveErrorMessage }); } finally { diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index a47db661445..5f082066ad4 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -2,6 +2,7 @@ import { GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui'; import Draggable from 'vuedraggable'; import { mapActions, mapState } from 'vuex'; +import { STATUS_CLOSED } from '~/issues/constants'; import { sprintf, __ } from '~/locale'; import { defaultSortableOptions } from '~/sortable/constants'; import { sortableStart, sortableEnd } from '~/sortable/utils'; @@ -158,10 +159,10 @@ export default { return this.isApolloBoard ? this.isLoadingMore : this.listsFlags[this.list.id]?.isLoadingMore; }, epicCreateFormVisible() { - return this.isEpicBoard && this.list.listType !== 'closed' && this.showEpicForm; + return this.isEpicBoard && this.list.listType !== STATUS_CLOSED && this.showEpicForm; }, issueCreateFormVisible() { - return !this.isEpicBoard && this.list.listType !== 'closed' && this.showIssueForm; + return !this.isEpicBoard && this.list.listType !== STATUS_CLOSED && this.showIssueForm; }, listRef() { // When list is draggable, the reference to the list needs to be accessed differently @@ -418,7 +419,6 @@ export default { v-if="loadingMore" size="sm" :label="$options.i18n.loadingMoreboardItems" - data-testid="count-loading-icon" /> <span v-if="showingAllItems">{{ showingAllItemsText }}</span> <span v-else>{{ paginatedIssueText }}</span> diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue index f4358315d45..7dc3e464af0 100644 --- a/app/assets/javascripts/boards/components/board_list_header.vue +++ b/app/assets/javascripts/boards/components/board_list_header.vue @@ -229,9 +229,6 @@ export default { context: { isSingleRequest: true, }, - skip() { - return this.isEpicBoard; - }, }, }, created() { @@ -426,7 +423,7 @@ export default { <div v-if="list.maxIssueCount !== 0"> • <gl-sprintf :message="__('%{issuesSize} with a limit of %{maxIssueCount}')"> - <template #issuesSize>{{ itemsTooltipLabel }}</template> + <template #issuesSize>{{ itemsCount }}</template> <template #maxIssueCount>{{ list.maxIssueCount }}</template> </gl-sprintf> </div> diff --git a/app/assets/javascripts/boards/components/board_top_bar.vue b/app/assets/javascripts/boards/components/board_top_bar.vue index fad57758be1..c186346b2ac 100644 --- a/app/assets/javascripts/boards/components/board_top_bar.vue +++ b/app/assets/javascripts/boards/components/board_top_bar.vue @@ -98,6 +98,7 @@ export default { <issue-board-filtered-search v-if="isIssueBoard" :board="board" + :is-swimlanes-on="isSwimlanesOn" @setFilters="$emit('setFilters', $event)" /> <epic-board-filtered-search 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 cdcc7b8e5a6..3c056f296e1 100644 --- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue @@ -52,6 +52,11 @@ export default { required: false, default: () => {}, }, + isSwimlanesOn: { + type: Boolean, + required: false, + default: false, + }, }, computed: { tokensCE() { @@ -203,6 +208,7 @@ export default { data-testid="issue-board-filtered-search" :tokens="tokens" :board="board" + :is-swimlanes-on="isSwimlanesOn" @setFilters="$emit('setFilters', $event)" /> </template> diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue index c3f7c7d3ca2..1f28974afd1 100644 --- a/app/assets/javascripts/boards/components/issue_due_date.vue +++ b/app/assets/javascripts/boards/components/issue_due_date.vue @@ -95,9 +95,12 @@ export default { class="board-card-info-icon gl-mr-2" name="calendar" /> - <time :class="{ 'text-danger': isPastDue }" datetime="date" class="board-card-info-text">{{ - body - }}</time> + <time + :class="{ 'text-danger': isPastDue }" + datetime="date" + class="gl-font-sm board-card-info-text" + >{{ body }}</time + > </span> <gl-tooltip :target="() => $refs.issueDueDate" :placement="tooltipPlacement"> <span class="bold">{{ __('Due date') }}</span> diff --git a/app/assets/javascripts/boards/components/issue_time_estimate.vue b/app/assets/javascripts/boards/components/issue_time_estimate.vue index bc12717a92d..611e875fa40 100644 --- a/app/assets/javascripts/boards/components/issue_time_estimate.vue +++ b/app/assets/javascripts/boards/components/issue_time_estimate.vue @@ -38,7 +38,7 @@ export default { <span> <span ref="issueTimeEstimate" class="board-card-info gl-mr-3 gl-text-secondary gl-cursor-help"> <gl-icon name="hourglass" class="board-card-info-icon gl-mr-2" /> - <time class="board-card-info-text">{{ timeEstimate }}</time> + <time class="gl-font-sm board-card-info-text">{{ timeEstimate }}</time> </span> <gl-tooltip :target="() => $refs.issueTimeEstimate" 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 43a2b13b81c..020edcb01b8 100644 --- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_title.vue @@ -5,6 +5,7 @@ import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.v import { joinPaths } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import autofocusonshow from '~/vue_shared/directives/autofocusonshow'; +import { titleQueries } from 'ee_else_ce/boards/constants'; export default { components: { @@ -19,6 +20,13 @@ export default { directives: { autofocusonshow, }, + inject: ['fullPath', 'issuableType', 'isEpicBoard', 'isApolloBoard'], + props: { + activeItem: { + type: Object, + required: true, + }, + }, data() { return { title: '', @@ -27,7 +35,10 @@ export default { }; }, computed: { - ...mapGetters({ item: 'activeBoardItem' }), + ...mapGetters(['activeBoardItem']), + item() { + return this.isApolloBoard ? this.activeItem : this.activeBoardItem; + }, pendingChangesStorageKey() { return this.getPendingChangesKey(this.item); }, @@ -67,8 +78,9 @@ export default { }, async setPendingState() { const pendingChanges = localStorage.getItem(this.pendingChangesStorageKey); + const shouldOpen = pendingChanges !== this.title; - if (pendingChanges) { + if (pendingChanges && shouldOpen) { this.title = pendingChanges; this.showChangesAlert = true; await this.$nextTick(); @@ -83,6 +95,26 @@ export default { this.showChangesAlert = false; localStorage.removeItem(this.pendingChangesStorageKey); }, + async setActiveBoardItemTitle() { + if (!this.isApolloBoard) { + await this.setActiveItemTitle({ title: this.title, projectPath: this.projectPath }); + return; + } + const { fullPath, issuableType, isEpicBoard, title } = this; + const workspacePath = isEpicBoard + ? { groupPath: fullPath } + : { projectPath: this.projectPath }; + await this.$apollo.mutate({ + mutation: titleQueries[issuableType].mutation, + variables: { + input: { + ...workspacePath, + iid: String(this.item.iid), + title, + }, + }, + }); + }, async setTitle() { this.$refs.sidebarItem.collapse(); @@ -92,7 +124,7 @@ export default { try { this.loading = true; - await this.setActiveItemTitle({ title: this.title, projectPath: this.projectPath }); + await this.setActiveBoardItemTitle(); localStorage.removeItem(this.pendingChangesStorageKey); this.showChangesAlert = false; } catch (e) { diff --git a/app/assets/javascripts/boards/constants.js b/app/assets/javascripts/boards/constants.js index b557dc9205e..d12270e58a4 100644 --- a/app/assets/javascripts/boards/constants.js +++ b/app/assets/javascripts/boards/constants.js @@ -12,6 +12,11 @@ import groupBoardQuery from './graphql/group_board.query.graphql'; import projectBoardQuery from './graphql/project_board.query.graphql'; import listIssuesQuery from './graphql/lists_issues.query.graphql'; +export const BoardType = { + project: 'project', + group: 'group', +}; + export const ListType = { assignee: 'assignee', milestone: 'milestone', diff --git a/app/assets/javascripts/boards/graphql/client/active_board_item.query.graphql b/app/assets/javascripts/boards/graphql/client/active_board_item.query.graphql new file mode 100644 index 00000000000..81b1b68a038 --- /dev/null +++ b/app/assets/javascripts/boards/graphql/client/active_board_item.query.graphql @@ -0,0 +1,7 @@ +#import "ee_else_ce/boards/graphql/issue.fragment.graphql" + +query activeBoardItem { + activeBoardItem @client { + ...Issue + } +} diff --git a/app/assets/javascripts/boards/graphql/client/set_active_board_item.mutation.graphql b/app/assets/javascripts/boards/graphql/client/set_active_board_item.mutation.graphql new file mode 100644 index 00000000000..cce558c649e --- /dev/null +++ b/app/assets/javascripts/boards/graphql/client/set_active_board_item.mutation.graphql @@ -0,0 +1,7 @@ +#import "ee_else_ce/boards/graphql/issue.fragment.graphql" + +mutation setActiveBoardItem($boardItem: Issue) { + setActiveBoardItem(boardItem: $boardItem) @client { + ...Issue + } +} |