diff options
Diffstat (limited to 'app/assets/javascripts/boards')
30 files changed, 448 insertions, 300 deletions
diff --git a/app/assets/javascripts/boards/boards_util.js b/app/assets/javascripts/boards/boards_util.js index c10241d00d7..e6c91c7ac1f 100644 --- a/app/assets/javascripts/boards/boards_util.js +++ b/app/assets/javascripts/boards/boards_util.js @@ -1,4 +1,5 @@ import { sortBy, cloneDeep } from 'lodash'; +import { isGid } from '~/graphql_shared/utils'; import { ListType, MilestoneIDs } from './constants'; export function getMilestone() { @@ -95,6 +96,9 @@ export function fullMilestoneId(id) { } export function fullLabelId(label) { + if (isGid(label.id)) { + return label.id; + } if (label.project_id && label.project_id !== null) { return `gid://gitlab/ProjectLabel/${label.id}`; } diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 1e780f9ef84..563bed6a6b8 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -83,7 +83,7 @@ export default { :data-item-path="item.referencePath" data-testid="board_card" class="board-card gl-p-5 gl-rounded-base" - @mouseup="toggleIssue($event)" + @click="toggleIssue($event)" > <board-card-inner :list="list" :item="item" :update-filters="true" /> </li> diff --git a/app/assets/javascripts/boards/components/board_content_sidebar.vue b/app/assets/javascripts/boards/components/board_content_sidebar.vue index 9bbb8a1a1b2..54668c9e88e 100644 --- a/app/assets/javascripts/boards/components/board_content_sidebar.vue +++ b/app/assets/javascripts/boards/components/board_content_sidebar.vue @@ -15,6 +15,7 @@ import SidebarDateWidget from '~/sidebar/components/date/sidebar_date_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 '~/vue_shared/components/sidebar/labels_select_widget/labels_select_root.vue'; +import { LabelType } from '~/vue_shared/components/sidebar/labels_select_widget/constants'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; export default { @@ -53,6 +54,9 @@ export default { allowLabelEdit: { default: false, }, + labelsFilterBasePath: { + default: '', + }, }, inheritAttrs: false, computed: { @@ -63,7 +67,7 @@ export default { 'groupPathForActiveIssue', 'projectPathForActiveIssue', ]), - ...mapState(['sidebarType', 'issuableType', 'isSettingLabels']), + ...mapState(['sidebarType', 'issuableType']), isIssuableSidebar() { return this.sidebarType === ISSUABLE; }, @@ -84,7 +88,15 @@ export default { }); }, attrWorkspacePath() { - return this.isGroupBoard ? this.groupPathForActiveIssue : undefined; + return this.isGroupBoard ? this.groupPathForActiveIssue : this.projectPathForActiveIssue; + }, + labelType() { + return this.isGroupBoard ? LabelType.group : LabelType.project; + }, + labelsFilterPath() { + return this.isGroupBoard + ? this.labelsFilterBasePath.replace(':project_path', this.projectPathForActiveIssue) + : this.labelsFilterBasePath; }, }, methods: { @@ -98,21 +110,19 @@ export default { handleClose() { this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType }); }, - handleUpdateSelectedLabels(input) { + handleUpdateSelectedLabels({ labels, id }) { this.setActiveBoardItemLabels({ - iid: this.activeBoardItem.iid, + id, projectPath: this.projectPathForActiveIssue, - addLabelIds: input.map((label) => getIdFromGraphQLId(label.id)), - removeLabelIds: this.activeBoardItem.labels - .filter((label) => !input.find((selected) => selected.id === label.id)) - .map((label) => label.id), + labelIds: labels.map((label) => getIdFromGraphQLId(label.id)), + labels, }); }, - handleLabelRemove(input) { + handleLabelRemove(removeLabelId) { this.setActiveBoardItemLabels({ iid: this.activeBoardItem.iid, projectPath: this.projectPathForActiveIssue, - removeLabelIds: [input], + removeLabelIds: [removeLabelId], }); }, }, @@ -207,14 +217,14 @@ export default { :full-path="projectPathForActiveIssue" :allow-label-remove="allowLabelEdit" :allow-multiselect="true" - :selected-labels="activeBoardItem.labels" - :labels-select-in-progress="isSettingLabels" :footer-create-label-title="createLabelTitle" :footer-manage-label-title="manageLabelTitle" :labels-create-title="createLabelTitle" - :labels-filter-base-path="projectPathForActiveIssue" + :labels-filter-base-path="labelsFilterPath" :attr-workspace-path="attrWorkspacePath" + workspace-type="project" :issuable-type="issuableType" + :label-create-type="labelType" @onLabelRemove="handleLabelRemove" @updateSelectedLabels="handleUpdateSelectedLabels" > diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue index 7f242dea644..6e6ada2d109 100644 --- a/app/assets/javascripts/boards/components/board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/board_filtered_search.vue @@ -1,6 +1,7 @@ <script> -import { pickBy } from 'lodash'; +import { pickBy, isEmpty } from 'lodash'; import { mapActions } from 'vuex'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { updateHistory, setUrlParams } from '~/lib/utils/url_utility'; import { __ } from '~/locale'; import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; @@ -19,6 +20,11 @@ export default { type: Array, required: true, }, + eeFilters: { + required: false, + type: Object, + default: () => ({}), + }, }, data() { return { @@ -26,57 +32,6 @@ export default { }; }, computed: { - urlParams() { - const { - authorUsername, - labelName, - assigneeUsername, - search, - milestoneTitle, - types, - weight, - } = this.filterParams; - let notParams = {}; - - if (Object.prototype.hasOwnProperty.call(this.filterParams, 'not')) { - notParams = pickBy( - { - 'not[label_name][]': this.filterParams.not.labelName, - 'not[author_username]': this.filterParams.not.authorUsername, - 'not[assignee_username]': this.filterParams.not.assigneeUsername, - 'not[types]': this.filterParams.not.types, - 'not[milestone_title]': this.filterParams.not.milestoneTitle, - 'not[weight]': this.filterParams.not.weight, - }, - undefined, - ); - } - - return { - ...notParams, - author_username: authorUsername, - 'label_name[]': labelName, - assignee_username: assigneeUsername, - milestone_title: milestoneTitle, - search, - types, - weight, - }; - }, - }, - methods: { - ...mapActions(['performSearch']), - handleFilter(filters) { - this.filterParams = this.getFilterParams(filters); - - updateHistory({ - url: setUrlParams(this.urlParams, window.location.href, true, false, true), - title: document.title, - replace: true, - }); - - this.performSearch(); - }, getFilteredSearchValue() { const { authorUsername, @@ -86,6 +41,8 @@ export default { milestoneTitle, types, weight, + epicId, + myReactionEmoji, } = this.filterParams; const filteredSearchValue = []; @@ -133,6 +90,20 @@ export default { }); } + if (myReactionEmoji) { + filteredSearchValue.push({ + type: 'my_reaction_emoji', + value: { data: myReactionEmoji, operator: '=' }, + }); + } + + if (epicId) { + filteredSearchValue.push({ + type: 'epic_id', + value: { data: epicId, operator: '=' }, + }); + } + if (this.filterParams['not[authorUsername]']) { filteredSearchValue.push({ type: 'author_username', @@ -177,12 +148,89 @@ export default { }); } + if (this.filterParams['not[epicId]']) { + filteredSearchValue.push({ + type: 'epic_id', + value: { data: this.filterParams['not[epicId]'], operator: '!=' }, + }); + } + + if (this.filterParams['not[myReactionEmoji]']) { + filteredSearchValue.push({ + type: 'my_reaction_emoji', + value: { data: this.filterParams['not[myReactionEmoji]'], operator: '!=' }, + }); + } + if (search) { filteredSearchValue.push(search); } return filteredSearchValue; }, + urlParams() { + const { + authorUsername, + labelName, + assigneeUsername, + search, + milestoneTitle, + types, + weight, + epicId, + myReactionEmoji, + } = this.filterParams; + + let notParams = {}; + + if (Object.prototype.hasOwnProperty.call(this.filterParams, 'not')) { + notParams = pickBy( + { + 'not[label_name][]': this.filterParams.not.labelName, + 'not[author_username]': this.filterParams.not.authorUsername, + 'not[assignee_username]': this.filterParams.not.assigneeUsername, + 'not[types]': this.filterParams.not.types, + 'not[milestone_title]': this.filterParams.not.milestoneTitle, + 'not[weight]': this.filterParams.not.weight, + 'not[epic_id]': this.filterParams.not.epicId, + 'not[my_reaction_emoji]': this.filterParams.not.myReactionEmoji, + }, + undefined, + ); + } + + return { + ...notParams, + author_username: authorUsername, + 'label_name[]': labelName, + assignee_username: assigneeUsername, + milestone_title: milestoneTitle, + search, + types, + weight, + epic_id: getIdFromGraphQLId(epicId), + my_reaction_emoji: myReactionEmoji, + }; + }, + }, + created() { + if (!isEmpty(this.eeFilters)) { + this.filterParams = this.eeFilters; + } + }, + methods: { + ...mapActions(['performSearch']), + handleFilter(filters) { + this.filterParams = this.getFilterParams(filters); + + updateHistory({ + url: setUrlParams(this.urlParams, window.location.href, true, false, true), + title: document.title, + replace: true, + }); + + this.performSearch(); + }, getFilterParams(filters = []) { const notFilters = filters.filter((item) => item.value.operator === '!='); const equalsFilters = filters.filter( @@ -216,6 +264,12 @@ export default { case 'weight': filterParams.weight = filter.value.data; break; + case 'epic_id': + filterParams.epicId = filter.value.data; + break; + case 'my_reaction_emoji': + filterParams.myReactionEmoji = filter.value.data; + break; case 'filtered-search-term': if (filter.value.data) plainText.push(filter.value.data); break; @@ -243,7 +297,7 @@ export default { namespace="" :tokens="tokens" :search-input-placeholder="$options.i18n.search" - :initial-filter-value="getFilteredSearchValue()" + :initial-filter-value="getFilteredSearchValue" @onFilter="handleFilter" /> </template> diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue index e939f0c0ebe..6ad57fd8985 100644 --- a/app/assets/javascripts/boards/components/board_form.vue +++ b/app/assets/javascripts/boards/components/board_form.vue @@ -2,10 +2,10 @@ import { GlModal, GlAlert } from '@gitlab/ui'; import { mapGetters, mapActions, mapState } from 'vuex'; import { TYPE_USER, TYPE_ITERATION, TYPE_MILESTONE } from '~/graphql_shared/constants'; -import { convertToGraphQLId } from '~/graphql_shared/utils'; +import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getParameterByName, visitUrl } from '~/lib/utils/url_utility'; import { __, s__ } from '~/locale'; -import { fullLabelId, fullBoardId } from '../boards_util'; +import { fullLabelId } from '../boards_util'; import { formType } from '../constants'; import createBoardMutation from '../graphql/board_create.mutation.graphql'; @@ -18,11 +18,11 @@ const boardDefaults = { name: '', labels: [], milestone: {}, - iteration_id: undefined, + iteration: {}, assignee: {}, weight: null, - hide_backlog_list: false, - hide_closed_list: false, + hideBacklogList: false, + hideClosedList: false, }; export default { @@ -57,39 +57,16 @@ export default { type: Boolean, required: true, }, - labelsPath: { - type: String, - required: true, - }, - labelsWebUrl: { - type: String, - required: true, - }, scopedIssueBoardFeatureEnabled: { type: Boolean, required: false, default: false, }, - projectId: { - type: Number, - required: false, - default: 0, - }, - groupId: { - type: Number, - required: false, - default: 0, - }, weights: { type: Array, required: false, default: () => [], }, - enableScopedLabels: { - type: Boolean, - required: false, - default: false, - }, currentBoard: { type: Object, required: true, @@ -167,17 +144,16 @@ export default { return destroyBoardMutation; }, baseMutationVariables() { - const { board } = this; - const variables = { - name: board.name, - hideBacklogList: board.hide_backlog_list, - hideClosedList: board.hide_closed_list, - }; + const { + board: { name, hideBacklogList, hideClosedList, id }, + } = this; - return board.id + const variables = { name, hideBacklogList, hideClosedList }; + + return id ? { ...variables, - id: fullBoardId(board.id), + id, } : { ...variables, @@ -191,11 +167,13 @@ export default { assigneeId: this.board.assignee?.id ? convertToGraphQLId(TYPE_USER, this.board.assignee.id) : null, + // Temporarily converting to milestone ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779 milestoneId: this.board.milestone?.id - ? convertToGraphQLId(TYPE_MILESTONE, this.board.milestone.id) + ? convertToGraphQLId(TYPE_MILESTONE, getIdFromGraphQLId(this.board.milestone.id)) : null, - iterationId: this.board.iteration_id - ? convertToGraphQLId(TYPE_ITERATION, this.board.iteration_id) + // Temporarily converting to iteration ID due to https://gitlab.com/gitlab-org/gitlab/-/issues/344779 + iterationId: this.board.iteration?.id + ? convertToGraphQLId(TYPE_ITERATION, getIdFromGraphQLId(this.board.iteration.id)) : null, }; }, @@ -249,7 +227,7 @@ export default { await this.$apollo.mutate({ mutation: this.deleteMutation, variables: { - id: fullBoardId(this.board.id), + id: this.board.id, }, }); }, @@ -285,19 +263,12 @@ export default { } }, setIteration(iterationId) { - this.board.iteration_id = iterationId; + this.$set(this.board, 'iteration', { + id: iterationId, + }); }, setBoardLabels(labels) { - labels.forEach((label) => { - if (label.set && !this.board.labels.find((l) => l.id === label.id)) { - this.board.labels.push({ - ...label, - textColor: label.text_color, - }); - } else if (!label.set) { - this.board.labels = this.board.labels.filter((selected) => selected.id !== label.id); - } - }); + this.board.labels = labels; }, setAssignee(assigneeId) { this.$set(this.board, 'assignee', { @@ -361,8 +332,8 @@ export default { </div> <board-configuration-options - :hide-backlog-list.sync="board.hide_backlog_list" - :hide-closed-list.sync="board.hide_closed_list" + :hide-backlog-list.sync="board.hideBacklogList" + :hide-closed-list.sync="board.hideClosedList" :readonly="readonly" /> @@ -371,11 +342,6 @@ export default { :collapse-scope="isNewForm" :board="board" :can-admin-board="canAdminBoard" - :labels-path="labelsPath" - :labels-web-url="labelsWebUrl" - :enable-scoped-labels="enableScopedLabels" - :project-id="projectId" - :group-id="groupId" :weights="weights" @set-iteration="setIteration" @set-board-labels="setBoardLabels" diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue index a8d71ab7a35..e985a368e64 100644 --- a/app/assets/javascripts/boards/components/board_list_header.vue +++ b/app/assets/javascripts/boards/components/board_list_header.vue @@ -15,6 +15,8 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; import { n__, s__, __ } from '~/locale'; import sidebarEventHub from '~/sidebar/event_hub'; import Tracking from '~/tracking'; +import { formatDate } from '~/lib/utils/datetime_utility'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import AccessorUtilities from '../../lib/utils/accessor'; import { inactiveId, LIST, ListType, toggleFormEventPrefix } from '../constants'; import eventHub from '../eventhub'; @@ -40,7 +42,7 @@ export default { directives: { GlTooltip: GlTooltipDirective, }, - mixins: [Tracking.mixin()], + mixins: [Tracking.mixin(), glFeatureFlagMixin()], inject: { boardId: { default: '', @@ -86,6 +88,13 @@ export default { listTitle() { return this.list?.label?.description || this.list?.assignee?.name || this.list.title || ''; }, + listIterationPeriod() { + const iteration = this.list?.iteration; + return iteration ? this.getIterationPeriod(iteration) : ''; + }, + isIterationList() { + return this.listType === ListType.iteration; + }, showListHeaderButton() { return !this.disabled && this.listType !== ListType.closed; }, @@ -96,7 +105,10 @@ export default { return this.listType === ListType.assignee && this.showListDetails; }, showIterationListDetails() { - return this.listType === ListType.iteration && this.showListDetails; + return this.isIterationList && this.showListDetails; + }, + iterationCadencesAvailable() { + return this.isIterationList && this.glFeatures.iterationCadences; }, showListDetails() { return !this.list.collapsed || !this.isSwimlanesHeader; @@ -208,6 +220,16 @@ export default { updateListFunction() { this.updateList({ listId: this.list.id, collapsed: this.list.collapsed }); }, + /** + * TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/344619 + * This method also exists as a utility function in ee/../iterations/utils.js + * Remove the duplication when the EE code is separated from this compoment. + */ + getIterationPeriod({ startDate, dueDate }) { + const start = formatDate(startDate, 'mmm d, yyyy', true); + const due = formatDate(dueDate, 'mmm d, yyyy', true); + return `${start} - ${due}`; + }, }, }; </script> @@ -307,6 +329,13 @@ export default { class="board-title-main-text gl-text-truncate" > {{ listTitle }} + <span + v-if="iterationCadencesAvailable" + class="gl-display-inline-block gl-text-gray-400" + data-testid="board-list-iteration-period" + > + {{ listIterationPeriod }}</span + > </span> <span v-if="listType === 'assignee'" diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue index 98027917221..71facba1378 100644 --- a/app/assets/javascripts/boards/components/boards_selector.vue +++ b/app/assets/javascripts/boards/components/boards_selector.vue @@ -9,17 +9,20 @@ import { GlModalDirective, } from '@gitlab/ui'; import { throttle } from 'lodash'; -import { mapGetters, mapState } from 'vuex'; +import { mapActions, mapGetters, mapState } from 'vuex'; import BoardForm from 'ee_else_ce/boards/components/board_form.vue'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import axios from '~/lib/utils/axios_utils'; import httpStatusCodes from '~/lib/utils/http_status'; +import { s__ } from '~/locale'; import eventHub from '../eventhub'; -import groupQuery from '../graphql/group_boards.query.graphql'; -import projectQuery from '../graphql/project_boards.query.graphql'; +import groupBoardsQuery from '../graphql/group_boards.query.graphql'; +import projectBoardsQuery from '../graphql/project_boards.query.graphql'; +import groupBoardQuery from '../graphql/group_board.query.graphql'; +import projectBoardQuery from '../graphql/project_board.query.graphql'; const MIN_BOARDS_TO_VIEW_RECENT = 10; @@ -39,10 +42,6 @@ export default { }, inject: ['fullPath', 'recentBoardsEndpoint'], props: { - currentBoard: { - type: Object, - required: true, - }, throttleDuration: { type: Number, default: 200, @@ -64,22 +63,6 @@ export default { type: Boolean, required: true, }, - labelsPath: { - type: String, - required: true, - }, - labelsWebUrl: { - type: String, - required: true, - }, - projectId: { - type: Number, - required: true, - }, - groupId: { - type: Number, - required: true, - }, scopedIssueBoardFeatureEnabled: { type: Boolean, required: true, @@ -88,11 +71,6 @@ export default { type: Array, required: true, }, - enabledScopedLabels: { - type: Boolean, - required: false, - default: false, - }, }, data() { return { @@ -107,14 +85,47 @@ export default { maxPosition: 0, filterTerm: '', currentPage: '', + board: {}, }; }, + apollo: { + board: { + query() { + return this.currentBoardQuery; + }, + variables() { + return { + fullPath: this.fullPath, + boardId: this.fullBoardId, + }; + }, + update(data) { + const board = data.workspace?.board; + return { + ...board, + labels: board?.labels?.nodes, + }; + }, + error() { + this.setError({ message: this.$options.i18n.errorFetchingBoard }); + }, + }, + }, computed: { - ...mapState(['boardType']), - ...mapGetters(['isGroupBoard']), + ...mapState(['boardType', 'fullBoardId']), + ...mapGetters(['isGroupBoard', 'isProjectBoard']), parentType() { return this.boardType; }, + currentBoardQueryCE() { + return this.isGroupBoard ? groupBoardQuery : projectBoardQuery; + }, + currentBoardQuery() { + return this.currentBoardQueryCE; + }, + isBoardLoading() { + return this.$apollo.queries.board.loading; + }, loading() { return this.loadingRecentBoards || Boolean(this.loadingBoards); }, @@ -123,9 +134,6 @@ export default { board.name.toLowerCase().includes(this.filterTerm.toLowerCase()), ); }, - board() { - return this.currentBoard; - }, showCreate() { return this.multipleIssueBoardsAvailable; }, @@ -158,6 +166,7 @@ export default { eventHub.$off('showBoardModal', this.showPage); }, methods: { + ...mapActions(['setError']), showPage(page) { this.currentPage = page; }, @@ -174,7 +183,7 @@ export default { })); }, boardQuery() { - return this.isGroupBoard ? groupQuery : projectQuery; + return this.isGroupBoard ? groupBoardsQuery : projectBoardsQuery; }, loadBoards(toggleDropdown = true) { if (toggleDropdown && this.boards.length > 0) { @@ -250,6 +259,9 @@ export default { this.hasScrollFade = this.isScrolledUp(); }, }, + i18n: { + errorFetchingBoard: s__('Board|An error occurred while fetching the board, please try again.'), + }, }; </script> @@ -260,6 +272,7 @@ export default { data-qa-selector="boards_dropdown" toggle-class="dropdown-menu-toggle js-dropdown-toggle" menu-class="flex-column dropdown-extended-height" + :loading="isBoardLoading" :text="board.name" @show="loadBoards" > @@ -354,15 +367,10 @@ export default { <board-form v-if="currentPage" - :labels-path="labelsPath" - :labels-web-url="labelsWebUrl" - :project-id="projectId" - :group-id="groupId" :can-admin-board="canAdminBoard" :scoped-issue-board-feature-enabled="scopedIssueBoardFeatureEnabled" :weights="weights" - :enable-scoped-labels="enabledScopedLabels" - :current-board="currentBoard" + :current-board="board" :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 b6c5ef955c6..bdb9c2be836 100644 --- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue @@ -1,13 +1,20 @@ <script> import { GlFilteredSearchToken } from '@gitlab/ui'; +import fuzzaldrinPlus from 'fuzzaldrin-plus'; import { mapActions } from 'vuex'; -import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue'; +import BoardFilteredSearch from 'ee_else_ce/boards/components/board_filtered_search.vue'; +import { BoardType } from '~/boards/constants'; +import axios from '~/lib/utils/axios_utils'; import issueBoardFilters from '~/boards/issue_board_filters'; import { TYPE_USER } from '~/graphql_shared/constants'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { __ } from '~/locale'; -import { DEFAULT_MILESTONES_GRAPHQL } from '~/vue_shared/components/filtered_search_bar/constants'; +import { + DEFAULT_MILESTONES_GRAPHQL, + TOKEN_TITLE_MY_REACTION, +} from '~/vue_shared/components/filtered_search_bar/constants'; import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; +import EmojiToken from '~/vue_shared/components/filtered_search_bar/tokens/emoji_token.vue'; import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'; import MilestoneToken from '~/vue_shared/components/filtered_search_bar/tokens/milestone_token.vue'; import WeightToken from '~/vue_shared/components/filtered_search_bar/tokens/weight_token.vue'; @@ -19,6 +26,7 @@ export default { }, i18n: { search: __('Search'), + epic: __('Epic'), label: __('Label'), author: __('Author'), assignee: __('Assignee'), @@ -31,6 +39,7 @@ export default { isNot: __('is not'), }, components: { BoardFilteredSearch }, + inject: ['isSignedIn'], props: { fullPath: { type: String, @@ -42,7 +51,15 @@ export default { }, }, computed: { - tokens() { + isGroupBoard() { + return this.boardType === BoardType.group; + }, + epicsGroupPath() { + return this.isGroupBoard + ? this.fullPath + : this.fullPath.slice(0, this.fullPath.lastIndexOf('/')); + }, + tokensCE() { const { label, is, @@ -103,6 +120,32 @@ export default { symbol: '~', fetchLabels, }, + ...(this.isSignedIn + ? [ + { + type: 'my_reaction_emoji', + title: TOKEN_TITLE_MY_REACTION, + icon: 'thumb-up', + token: EmojiToken, + unique: true, + fetchEmojis: (search = '') => { + // TODO: Switch to GraphQL query when backend is ready: https://gitlab.com/gitlab-org/gitlab/-/issues/339694 + return axios + .get(`${gon.relative_url_root || ''}/-/autocomplete/award_emojis`) + .then(({ data }) => { + if (search) { + return { + data: fuzzaldrinPlus.filter(data, search, { + key: ['name'], + }), + }; + } + return { data }; + }); + }, + }, + ] + : []), { type: 'milestone_title', title: milestone, @@ -117,7 +160,6 @@ export default { icon: 'issues', title: type, type: 'types', - operators: [{ value: '=', description: is }], token: GlFilteredSearchToken, unique: true, options: [ @@ -134,6 +176,9 @@ export default { }, ]; }, + tokens() { + return this.tokensCE; + }, }, methods: { ...mapActions(['fetchMilestones']), diff --git a/app/assets/javascripts/boards/components/new_board_button.vue b/app/assets/javascripts/boards/components/new_board_button.vue new file mode 100644 index 00000000000..f7914c636cc --- /dev/null +++ b/app/assets/javascripts/boards/components/new_board_button.vue @@ -0,0 +1,47 @@ +<script> +import { GlButton, GlModalDirective } from '@gitlab/ui'; +import { formType } from '~/boards/constants'; +import eventHub from '~/boards/eventhub'; +import { s__ } from '~/locale'; +import Tracking from '~/tracking'; +import GitlabExperiment from '~/experimentation/components/gitlab_experiment.vue'; + +export default { + components: { + GlButton, + GitlabExperiment, + }, + directives: { + GlModalDirective, + }, + mixins: [Tracking.mixin()], + inject: ['multipleIssueBoardsAvailable', 'canAdminBoard'], + computed: { + canShowCreateButton() { + return this.canAdminBoard && this.multipleIssueBoardsAvailable; + }, + createButtonText() { + return s__('Boards|New board'); + }, + }, + methods: { + showDialog() { + this.track('click_button', { label: 'create_board' }); + eventHub.$emit('showBoardModal', formType.new); + }, + }, +}; +</script> + +<template> + <gitlab-experiment name="prominent_create_board_btn"> + <template #control> </template> + <template #candidate> + <div v-if="canShowCreateButton" class="gl-ml-1 gl-mr-3 gl-display-flex gl-align-items-center"> + <gl-button data-qa-selector="new_board_button" @click.prevent="showDialog"> + {{ createButtonText }} + </gl-button> + </div> + </template> + </gitlab-experiment> +</template> diff --git a/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue b/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue index e74463825c5..ec53947fd5f 100644 --- a/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue +++ b/app/assets/javascripts/boards/components/sidebar/board_sidebar_labels_select.vue @@ -91,9 +91,7 @@ export default { try { const addLabelIds = payload.filter((label) => label.set).map((label) => label.id); - const removeLabelIds = this.selectedLabels - .filter((label) => !payload.find((selected) => selected.id === label.id)) - .map((label) => label.id); + const removeLabelIds = payload.filter((label) => !label.set).map((label) => label.id); const input = { addLabelIds, @@ -164,7 +162,7 @@ export default { :labels-list-title="__('Select label')" :dropdown-button-text="__('Choose labels')" :is-editing="edit" - variant="embedded" + variant="sidebar" class="gl-display-block labels gl-w-full" @updateSelectedLabels="setLabels" > diff --git a/app/assets/javascripts/boards/graphql.js b/app/assets/javascripts/boards/graphql.js index d8d16184936..64938cb42ed 100644 --- a/app/assets/javascripts/boards/graphql.js +++ b/app/assets/javascripts/boards/graphql.js @@ -17,6 +17,5 @@ export const gqlClient = createDefaultClient( fragmentMatcher, }, - assumeImmutableResults: true, }, ); diff --git a/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql b/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql index 3eb23f62940..0e1d11727cf 100644 --- a/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/board_list_create.mutation.graphql @@ -1,6 +1,6 @@ #import "./board_list.fragment.graphql" -mutation CreateBoardList($boardId: BoardID!, $backlog: Boolean, $labelId: LabelID) { +mutation createBoardList($boardId: BoardID!, $backlog: Boolean, $labelId: LabelID) { boardListCreate(input: { boardId: $boardId, backlog: $backlog, labelId: $labelId }) { list { ...BoardListFragment diff --git a/app/assets/javascripts/boards/graphql/board_lists.query.graphql b/app/assets/javascripts/boards/graphql/board_lists.query.graphql index 734867c77e9..47e87907d76 100644 --- a/app/assets/javascripts/boards/graphql/board_lists.query.graphql +++ b/app/assets/javascripts/boards/graphql/board_lists.query.graphql @@ -1,6 +1,6 @@ #import "ee_else_ce/boards/graphql/board_list.fragment.graphql" -query ListIssues( +query BoardLists( $fullPath: ID! $boardId: ID! $filters: BoardIssueInput diff --git a/app/assets/javascripts/boards/graphql/board_scope.fragment.graphql b/app/assets/javascripts/boards/graphql/board_scope.fragment.graphql new file mode 100644 index 00000000000..57f51822d91 --- /dev/null +++ b/app/assets/javascripts/boards/graphql/board_scope.fragment.graphql @@ -0,0 +1,6 @@ +fragment BoardScopeFragment on Board { + id + name + hideBacklogList + hideClosedList +} diff --git a/app/assets/javascripts/boards/graphql/group_board.query.graphql b/app/assets/javascripts/boards/graphql/group_board.query.graphql new file mode 100644 index 00000000000..77c8e0378f0 --- /dev/null +++ b/app/assets/javascripts/boards/graphql/group_board.query.graphql @@ -0,0 +1,9 @@ +#import "ee_else_ce/boards/graphql/board_scope.fragment.graphql" + +query GroupBoard($fullPath: ID!, $boardId: ID!) { + workspace: group(fullPath: $fullPath) { + board(id: $boardId) { + ...BoardScopeFragment + } + } +} diff --git a/app/assets/javascripts/boards/graphql/group_board_iterations.query.graphql b/app/assets/javascripts/boards/graphql/group_board_iterations.query.graphql deleted file mode 100644 index 1c382c4747b..00000000000 --- a/app/assets/javascripts/boards/graphql/group_board_iterations.query.graphql +++ /dev/null @@ -1,10 +0,0 @@ -query GroupBoardIterations($fullPath: ID!, $title: String) { - group(fullPath: $fullPath) { - iterations(includeAncestors: true, title: $title) { - nodes { - id - title - } - } - } -} diff --git a/app/assets/javascripts/boards/graphql/group_projects.query.graphql b/app/assets/javascripts/boards/graphql/group_projects.query.graphql index 3218c06357c..c5732bbaff3 100644 --- a/app/assets/javascripts/boards/graphql/group_projects.query.graphql +++ b/app/assets/javascripts/boards/graphql/group_projects.query.graphql @@ -1,6 +1,6 @@ #import "~/graphql_shared/fragments/pageInfo.fragment.graphql" -query getGroupProjects($fullPath: ID!, $search: String, $after: String) { +query boardsGetGroupProjects($fullPath: ID!, $search: String, $after: String) { group(fullPath: $fullPath) { projects(search: $search, after: $after, first: 100, includeSubgroups: true) { nodes { diff --git a/app/assets/javascripts/boards/graphql/issue_move_list.mutation.graphql b/app/assets/javascripts/boards/graphql/issue_move_list.mutation.graphql index 3c574fd8c87..570731ecac6 100644 --- a/app/assets/javascripts/boards/graphql/issue_move_list.mutation.graphql +++ b/app/assets/javascripts/boards/graphql/issue_move_list.mutation.graphql @@ -1,6 +1,6 @@ #import "ee_else_ce/boards/graphql/issue.fragment.graphql" -mutation IssueMoveList( +mutation issueMoveList( $projectPath: ID! $iid: String! $boardId: ID! diff --git a/app/assets/javascripts/boards/graphql/lists_issues.query.graphql b/app/assets/javascripts/boards/graphql/lists_issues.query.graphql index 787dd77b901..9f93bc6d5bf 100644 --- a/app/assets/javascripts/boards/graphql/lists_issues.query.graphql +++ b/app/assets/javascripts/boards/graphql/lists_issues.query.graphql @@ -1,6 +1,6 @@ #import "ee_else_ce/boards/graphql/issue.fragment.graphql" -query ListIssues( +query BoardListEE( $fullPath: ID! $boardId: ID! $id: ID diff --git a/app/assets/javascripts/boards/graphql/project_board.query.graphql b/app/assets/javascripts/boards/graphql/project_board.query.graphql new file mode 100644 index 00000000000..6e4cd6bed57 --- /dev/null +++ b/app/assets/javascripts/boards/graphql/project_board.query.graphql @@ -0,0 +1,9 @@ +#import "ee_else_ce/boards/graphql/board_scope.fragment.graphql" + +query ProjectBoard($fullPath: ID!, $boardId: ID!) { + workspace: project(fullPath: $fullPath) { + board(id: $boardId) { + ...BoardScopeFragment + } + } +} diff --git a/app/assets/javascripts/boards/graphql/project_board_iterations.query.graphql b/app/assets/javascripts/boards/graphql/project_board_iterations.query.graphql deleted file mode 100644 index 078151a275a..00000000000 --- a/app/assets/javascripts/boards/graphql/project_board_iterations.query.graphql +++ /dev/null @@ -1,10 +0,0 @@ -query ProjectBoardIterations($fullPath: ID!, $title: String) { - project(fullPath: $fullPath) { - iterations(includeAncestors: true, title: $title) { - nodes { - id - title - } - } - } -} diff --git a/app/assets/javascripts/boards/graphql/project_milestones.query.graphql b/app/assets/javascripts/boards/graphql/project_milestones.query.graphql index 724b7f5a34c..61c9ddded9b 100644 --- a/app/assets/javascripts/boards/graphql/project_milestones.query.graphql +++ b/app/assets/javascripts/boards/graphql/project_milestones.query.graphql @@ -1,4 +1,4 @@ -query projectMilestones( +query boardProjectMilestones( $fullPath: ID! $state: MilestoneStateEnum $includeAncestors: Boolean diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index b6b1094fb3a..6fa8dd63245 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -13,9 +13,10 @@ import FilteredSearchBoards from '~/boards/filtered_search_boards'; import initBoardsFilteredSearch from '~/boards/mount_filtered_search_issue_boards'; import store from '~/boards/stores'; import toggleFocusMode from '~/boards/toggle_focus'; -import { NavigationType, parseBoolean } from '~/lib/utils/common_utils'; +import { NavigationType, isLoggedIn, parseBoolean } from '~/lib/utils/common_utils'; import { fullBoardId } from './boards_util'; import boardConfigToggle from './config_toggle'; +import initNewBoard from './new_board'; import { gqlClient } from './graphql'; import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher'; @@ -109,7 +110,7 @@ export default () => { }); if (gon?.features?.issueBoardsFilteredSearch) { - initBoardsFilteredSearch(apolloProvider); + initBoardsFilteredSearch(apolloProvider, isLoggedIn()); } mountBoardApp($boardApp); @@ -130,6 +131,7 @@ export default () => { } boardConfigToggle(); + initNewBoard(); toggleFocusMode(); toggleLabels(); @@ -142,5 +144,7 @@ export default () => { fullPath: $boardApp.dataset.fullPath, rootPath: $boardApp.dataset.boardsEndpoint, recentBoardsEndpoint: $boardApp.dataset.recentBoardsEndpoint, + allowScopedLabels: $boardApp.dataset.scopedLabels, + labelsManagePath: $boardApp.dataset.labelsManagePath, }); }; diff --git a/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js b/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js index 7732091ef34..1ea74d5685c 100644 --- a/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js +++ b/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js @@ -1,10 +1,10 @@ import Vue from 'vue'; -import IssueBoardFilteredSearch from '~/boards/components/issue_board_filtered_search.vue'; +import IssueBoardFilteredSearch from 'ee_else_ce/boards/components/issue_board_filtered_search.vue'; import store from '~/boards/stores'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { queryToObject } from '~/lib/utils/url_utility'; -export default (apolloProvider) => { +export default (apolloProvider, isSignedIn) => { const el = document.getElementById('js-issue-board-filtered-search'); const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true }); @@ -20,6 +20,7 @@ export default (apolloProvider) => { el, provide: { initialFilterParams, + isSignedIn, }, store, // TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/324094 apolloProvider, diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js index a3a8ad06c43..ed32579a9c3 100644 --- a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js +++ b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js @@ -1,23 +1,32 @@ +import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue'; import store from '~/boards/stores'; import createDefaultClient from '~/lib/graphql'; import { parseBoolean } from '~/lib/utils/common_utils'; +import introspectionQueryResultData from '~/sidebar/fragmentTypes.json'; Vue.use(VueApollo); +const fragmentMatcher = new IntrospectionFragmentMatcher({ + introspectionQueryResultData, +}); + const apolloProvider = new VueApollo({ defaultClient: createDefaultClient( {}, { - assumeImmutableResults: true, + cacheConfig: { + fragmentMatcher, + }, }, ), }); export default (params = {}) => { const boardsSwitcherElement = document.getElementById('js-multiple-boards-switcher'); + const { dataset } = boardsSwitcherElement; return new Vue({ el: boardsSwitcherElement, components: { @@ -29,18 +38,16 @@ export default (params = {}) => { fullPath: params.fullPath, rootPath: params.rootPath, recentBoardsEndpoint: params.recentBoardsEndpoint, + allowScopedLabels: params.allowScopedLabels, + labelsManagePath: params.labelsManagePath, + allowLabelCreate: parseBoolean(dataset.canAdminBoard), }, data() { - const { dataset } = boardsSwitcherElement; - const boardsSelectorProps = { ...dataset, - currentBoard: JSON.parse(dataset.currentBoard), hasMissingBoards: parseBoolean(dataset.hasMissingBoards), canAdminBoard: parseBoolean(dataset.canAdminBoard), multipleIssueBoardsAvailable: parseBoolean(dataset.multipleIssueBoardsAvailable), - projectId: dataset.projectId ? Number(dataset.projectId) : 0, - groupId: Number(dataset.groupId), scopedIssueBoardFeatureEnabled: parseBoolean(dataset.scopedIssueBoardFeatureEnabled), weights: JSON.parse(dataset.weights), }; diff --git a/app/assets/javascripts/boards/new_board.js b/app/assets/javascripts/boards/new_board.js new file mode 100644 index 00000000000..34f2fea79a9 --- /dev/null +++ b/app/assets/javascripts/boards/new_board.js @@ -0,0 +1,29 @@ +import Vue from 'vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import { getExperimentVariant } from '~/experimentation/utils'; +import { CANDIDATE_VARIANT } from '~/experimentation/constants'; +import NewBoardButton from './components/new_board_button.vue'; + +export default () => { + if (getExperimentVariant('prominent_create_board_btn') !== CANDIDATE_VARIANT) { + return; + } + + const el = document.querySelector('.js-new-board'); + + if (!el) { + return; + } + + // eslint-disable-next-line no-new + new Vue({ + el, + provide: { + multipleIssueBoardsAvailable: parseBoolean(el.dataset.multipleIssueBoardsAvailable), + canAdminBoard: parseBoolean(el.dataset.canAdminBoard), + }, + render(h) { + return h(NewBoardButton); + }, + }); +}; diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js index ca993e75cf9..3a96e535cf7 100644 --- a/app/assets/javascripts/boards/stores/actions.js +++ b/app/assets/javascripts/boards/stores/actions.js @@ -36,13 +36,11 @@ import { } from '../boards_util'; import { gqlClient } from '../graphql'; import boardLabelsQuery from '../graphql/board_labels.query.graphql'; -import groupBoardIterationsQuery from '../graphql/group_board_iterations.query.graphql'; import groupBoardMilestonesQuery from '../graphql/group_board_milestones.query.graphql'; import groupProjectsQuery from '../graphql/group_projects.query.graphql'; import issueCreateMutation from '../graphql/issue_create.mutation.graphql'; import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql'; import listsIssuesQuery from '../graphql/lists_issues.query.graphql'; -import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql'; import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql'; import * as types from './mutation_types'; @@ -203,52 +201,6 @@ export default { }); }, - fetchIterations({ state, commit }, title) { - commit(types.RECEIVE_ITERATIONS_REQUEST); - - const { fullPath, boardType } = state; - - const variables = { - fullPath, - title, - }; - - let query; - if (boardType === BoardType.project) { - query = projectBoardIterationsQuery; - } - if (boardType === BoardType.group) { - query = groupBoardIterationsQuery; - } - - if (!query) { - // eslint-disable-next-line @gitlab/require-i18n-strings - throw new Error('Unknown board type'); - } - - return gqlClient - .query({ - query, - variables, - }) - .then(({ data }) => { - const errors = data[boardType]?.errors; - const iterations = data[boardType]?.iterations.nodes; - - if (errors?.[0]) { - throw new Error(errors[0]); - } - - commit(types.RECEIVE_ITERATIONS_SUCCESS, iterations); - - return iterations; - }) - .catch((e) => { - commit(types.RECEIVE_ITERATIONS_FAILURE); - throw e; - }); - }, - fetchMilestones({ state, commit }, searchTerm) { commit(types.RECEIVE_MILESTONES_REQUEST); @@ -656,30 +608,45 @@ export default { }, setActiveIssueLabels: async ({ commit, getters }, input) => { - commit(types.SET_LABELS_LOADING, true); const { activeBoardItem } = getters; - const { data } = await gqlClient.mutate({ - mutation: issueSetLabelsMutation, - variables: { - input: { - iid: input.iid || String(activeBoardItem.iid), - addLabelIds: input.addLabelIds ?? [], - removeLabelIds: input.removeLabelIds ?? [], - projectPath: input.projectPath, + + if (!gon.features?.labelsWidget) { + const { data } = await gqlClient.mutate({ + mutation: issueSetLabelsMutation, + variables: { + input: { + iid: input.iid || String(activeBoardItem.iid), + labelIds: input.labelsId ?? undefined, + addLabelIds: input.addLabelIds ?? [], + removeLabelIds: input.removeLabelIds ?? [], + projectPath: input.projectPath, + }, }, - }, - }); + }); - commit(types.SET_LABELS_LOADING, false); + if (data.updateIssue?.errors?.length > 0) { + throw new Error(data.updateIssue.errors); + } + + commit(types.UPDATE_BOARD_ITEM_BY_ID, { + itemId: data.updateIssue?.issue?.id || activeBoardItem.id, + prop: 'labels', + value: data.updateIssue?.issue?.labels.nodes, + }); - if (data.updateIssue?.errors?.length > 0) { - throw new Error(data.updateIssue.errors); + return; } + let labels = input?.labels || []; + if (input.removeLabelIds) { + labels = activeBoardItem.labels.filter( + (label) => input.removeLabelIds[0] !== getIdFromGraphQLId(label.id), + ); + } commit(types.UPDATE_BOARD_ITEM_BY_ID, { - itemId: data.updateIssue?.issue?.id || activeBoardItem.id, + itemId: input.id || activeBoardItem.id, prop: 'labels', - value: data.updateIssue.issue.labels.nodes, + value: labels, }); }, diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js index 26b785932bb..31b78014525 100644 --- a/app/assets/javascripts/boards/stores/mutation_types.js +++ b/app/assets/javascripts/boards/stores/mutation_types.js @@ -28,7 +28,6 @@ export const ADD_BOARD_ITEM_TO_LIST = 'ADD_BOARD_ITEM_TO_LIST'; export const REMOVE_BOARD_ITEM_FROM_LIST = 'REMOVE_BOARD_ITEM_FROM_LIST'; export const SET_ACTIVE_ID = 'SET_ACTIVE_ID'; export const UPDATE_BOARD_ITEM_BY_ID = 'UPDATE_BOARD_ITEM_BY_ID'; -export const SET_LABELS_LOADING = 'SET_LABELS_LOADING'; export const SET_ASSIGNEE_LOADING = 'SET_ASSIGNEE_LOADING'; export const RESET_ISSUES = 'RESET_ISSUES'; export const REQUEST_GROUP_PROJECTS = 'REQUEST_GROUP_PROJECTS'; @@ -42,7 +41,3 @@ export const ADD_LIST_TO_HIGHLIGHTED_LISTS = 'ADD_LIST_TO_HIGHLIGHTED_LISTS'; export const REMOVE_LIST_FROM_HIGHLIGHTED_LISTS = 'REMOVE_LIST_FROM_HIGHLIGHTED_LISTS'; export const RESET_BOARD_ITEM_SELECTION = 'RESET_BOARD_ITEM_SELECTION'; export const SET_ERROR = 'SET_ERROR'; - -export const RECEIVE_ITERATIONS_REQUEST = 'RECEIVE_ITERATIONS_REQUEST'; -export const RECEIVE_ITERATIONS_SUCCESS = 'RECEIVE_ITERATIONS_SUCCESS'; -export const RECEIVE_ITERATIONS_FAILURE = 'RECEIVE_ITERATIONS_FAILURE'; diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js index d381c076c19..2a2ce7652e6 100644 --- a/app/assets/javascripts/boards/stores/mutations.js +++ b/app/assets/javascripts/boards/stores/mutations.js @@ -64,20 +64,6 @@ export default { ); }, - [mutationTypes.RECEIVE_ITERATIONS_REQUEST](state) { - state.iterationsLoading = true; - }, - - [mutationTypes.RECEIVE_ITERATIONS_SUCCESS](state, iterations) { - state.iterations = iterations; - state.iterationsLoading = false; - }, - - [mutationTypes.RECEIVE_ITERATIONS_FAILURE](state) { - state.iterationsLoading = false; - state.error = __('Failed to load iterations.'); - }, - [mutationTypes.SET_ACTIVE_ID](state, { id, sidebarType }) { state.activeId = id; state.sidebarType = sidebarType; @@ -195,10 +181,6 @@ export default { Vue.set(state.boardItems[itemId], prop, value); }, - [mutationTypes.SET_LABELS_LOADING](state, isLoading) { - state.isSettingLabels = isLoading; - }, - [mutationTypes.SET_ASSIGNEE_LOADING](state, isLoading) { state.isSettingAssignees = isLoading; }, diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js index 2a6605e687b..80c51c966d2 100644 --- a/app/assets/javascripts/boards/stores/state.js +++ b/app/assets/javascripts/boards/stores/state.js @@ -12,7 +12,6 @@ export default () => ({ listsFlags: {}, boardItemsByListId: {}, backupItemsList: [], - isSettingLabels: false, isSettingAssignees: false, pageInfoByListId: {}, boardItems: {}, |