diff options
Diffstat (limited to 'app/assets/javascripts/boards')
16 files changed, 695 insertions, 13 deletions
diff --git a/app/assets/javascripts/boards/components/board_blank_state.vue b/app/assets/javascripts/boards/components/board_blank_state.vue index d8b0b60c183..9f26337d153 100644 --- a/app/assets/javascripts/boards/components/board_blank_state.vue +++ b/app/assets/javascripts/boards/components/board_blank_state.vue @@ -1,6 +1,6 @@ <script> import { __ } from '~/locale'; -/* global ListLabel */ +import ListLabel from '~/boards/models/label'; import Cookies from 'js-cookie'; import boardsStore from '../stores/boards_store'; @@ -30,13 +30,17 @@ export default { }); // Save the labels - gl.boardService + boardsStore .generateDefaultLists() .then(res => res.data) .then(data => { data.forEach(listObj => { const list = boardsStore.findList('title', listObj.title); + if (!list) { + return; + } + list.id = listObj.id; list.label.id = listObj.label.id; list.getIssues().catch(() => { @@ -69,8 +73,7 @@ export default { <span :style="{ backgroundColor: label.color }" class="label-color position-relative d-inline-block rounded" - > - </span> + ></span> {{ label.title }} </li> </ul> diff --git a/app/assets/javascripts/boards/components/board_card.vue b/app/assets/javascripts/boards/components/board_card.vue index 179148b6887..faf722f61af 100644 --- a/app/assets/javascripts/boards/components/board_card.vue +++ b/app/assets/javascripts/boards/components/board_card.vue @@ -83,6 +83,7 @@ export default { }" :index="index" :data-issue-id="issue.id" + data-qa-selector="board_card" class="board-card p-3 rounded" @mousedown="mouseDown" @mousemove="mouseMove" diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue new file mode 100644 index 00000000000..ebf48cee2ae --- /dev/null +++ b/app/assets/javascripts/boards/components/board_form.vue @@ -0,0 +1,219 @@ +<script> +import { __ } from '~/locale'; +import Flash from '~/flash'; +import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue'; +import { visitUrl } from '~/lib/utils/url_utility'; +import boardsStore from '~/boards/stores/boards_store'; + +const boardDefaults = { + id: false, + name: '', + labels: [], + milestone_id: undefined, + assignee: {}, + assignee_id: undefined, + weight: null, +}; + +export default { + components: { + BoardScope: () => import('ee_component/boards/components/board_scope.vue'), + DeprecatedModal, + }, + props: { + canAdminBoard: { + type: Boolean, + required: true, + }, + milestonePath: { + type: String, + required: true, + }, + labelsPath: { + 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, + }, + scopedLabelsDocumentationLink: { + type: String, + required: false, + default: '#', + }, + }, + data() { + return { + board: { ...boardDefaults, ...this.currentBoard }, + currentBoard: boardsStore.state.currentBoard, + currentPage: boardsStore.state.currentPage, + isLoading: false, + }; + }, + computed: { + isNewForm() { + return this.currentPage === 'new'; + }, + isDeleteForm() { + return this.currentPage === 'delete'; + }, + isEditForm() { + return this.currentPage === 'edit'; + }, + isVisible() { + return this.currentPage !== ''; + }, + buttonText() { + if (this.isNewForm) { + return __('Create board'); + } + if (this.isDeleteForm) { + return __('Delete'); + } + return __('Save changes'); + }, + buttonKind() { + if (this.isNewForm) { + return 'success'; + } + if (this.isDeleteForm) { + return 'danger'; + } + return 'info'; + }, + title() { + if (this.isNewForm) { + return __('Create new board'); + } + if (this.isDeleteForm) { + return __('Delete board'); + } + if (this.readonly) { + return __('Board scope'); + } + return __('Edit board'); + }, + readonly() { + return !this.canAdminBoard; + }, + submitDisabled() { + return this.isLoading || this.board.name.length === 0; + }, + }, + mounted() { + this.resetFormState(); + if (this.$refs.name) { + this.$refs.name.focus(); + } + }, + methods: { + submit() { + if (this.board.name.length === 0) return; + this.isLoading = true; + if (this.isDeleteForm) { + gl.boardService + .deleteBoard(this.currentBoard) + .then(() => { + visitUrl(boardsStore.rootPath); + }) + .catch(() => { + Flash(__('Failed to delete board. Please try again.')); + this.isLoading = false; + }); + } else { + gl.boardService + .createBoard(this.board) + .then(resp => resp.data) + .then(data => { + visitUrl(data.board_path); + }) + .catch(() => { + Flash(__('Unable to save your changes. Please try again.')); + this.isLoading = false; + }); + } + }, + cancel() { + boardsStore.showPage(''); + }, + resetFormState() { + if (this.isNewForm) { + // Clear the form when we open the "New board" modal + this.board = { ...boardDefaults }; + } else if (this.currentBoard && Object.keys(this.currentBoard).length) { + this.board = { ...boardDefaults, ...this.currentBoard }; + } + }, + }, +}; +</script> + +<template> + <deprecated-modal + v-show="isVisible" + :hide-footer="readonly" + :title="title" + :primary-button-label="buttonText" + :kind="buttonKind" + :submit-disabled="submitDisabled" + modal-dialog-class="board-config-modal" + @cancel="cancel" + @submit="submit" + > + <template slot="body"> + <p v-if="isDeleteForm">{{ __('Are you sure you want to delete this board?') }}</p> + <form v-else class="js-board-config-modal" @submit.prevent> + <div v-if="!readonly" class="append-bottom-20"> + <label class="form-section-title label-bold" for="board-new-name">{{ + __('Board name') + }}</label> + <input + id="board-new-name" + ref="name" + v-model="board.name" + class="form-control" + type="text" + :placeholder="__('Enter board name')" + @keyup.enter="submit" + /> + </div> + + <board-scope + v-if="scopedIssueBoardFeatureEnabled" + :collapse-scope="isNewForm" + :board="board" + :can-admin-board="canAdminBoard" + :milestone-path="milestonePath" + :labels-path="labelsPath" + :scoped-labels-documentation-link="scopedLabelsDocumentationLink" + :enable-scoped-labels="enableScopedLabels" + :project-id="projectId" + :group-id="groupId" + :weights="weights" + /> + </form> + </template> + </deprecated-modal> +</template> diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 787ff110bf8..de41698ca04 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable @gitlab/vue-i18n/no-bare-strings */ import Sortable from 'sortablejs'; import { GlLoadingIcon } from '@gitlab/ui'; import boardNewIssue from './board_new_issue.vue'; @@ -226,6 +227,7 @@ export default { <div :class="{ 'd-none': !list.isExpanded, 'd-flex flex-column': list.isExpanded }" class="board-list-component position-relative h-100" + data-qa-selector="board_list_cards_area" > <div v-if="loading" class="board-list-loading text-center" :aria-label="__('Loading issues')"> <gl-loading-icon /> diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index 2ace0060c42..ba1fe9202fc 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -22,6 +22,8 @@ export default Vue.extend({ components: { AssigneeTitle, Assignees, + SidebarEpicsSelect: () => + import('ee_component/sidebar/components/sidebar_item_epics_select.vue'), RemoveBtn, Subscriptions, TimeTracker, diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue new file mode 100644 index 00000000000..7296426549a --- /dev/null +++ b/app/assets/javascripts/boards/components/boards_selector.vue @@ -0,0 +1,335 @@ +<script> +import { throttle } from 'underscore'; +import { + GlLoadingIcon, + GlSearchBoxByType, + GlDropdown, + GlDropdownDivider, + GlDropdownHeader, + GlDropdownItem, +} from '@gitlab/ui'; + +import Icon from '~/vue_shared/components/icon.vue'; +import httpStatusCodes from '~/lib/utils/http_status'; +import boardsStore from '../stores/boards_store'; +import BoardForm from './board_form.vue'; + +const MIN_BOARDS_TO_VIEW_RECENT = 10; + +export default { + name: 'BoardsSelector', + components: { + Icon, + BoardForm, + GlLoadingIcon, + GlSearchBoxByType, + GlDropdown, + GlDropdownDivider, + GlDropdownHeader, + GlDropdownItem, + }, + props: { + currentBoard: { + type: Object, + required: true, + }, + milestonePath: { + type: String, + required: true, + }, + throttleDuration: { + type: Number, + default: 200, + }, + boardBaseUrl: { + type: String, + required: true, + }, + hasMissingBoards: { + type: Boolean, + required: true, + }, + canAdminBoard: { + type: Boolean, + required: true, + }, + multipleIssueBoardsAvailable: { + type: Boolean, + required: true, + }, + labelsPath: { + type: String, + required: true, + }, + projectId: { + type: Number, + required: true, + }, + groupId: { + type: Number, + required: true, + }, + scopedIssueBoardFeatureEnabled: { + type: Boolean, + required: true, + }, + weights: { + type: Array, + required: true, + }, + enabledScopedLabels: { + type: Boolean, + required: false, + default: false, + }, + scopedLabelsDocumentationLink: { + type: String, + required: false, + default: '#', + }, + }, + data() { + return { + loading: true, + hasScrollFade: false, + scrollFadeInitialized: false, + boards: [], + recentBoards: [], + state: boardsStore.state, + throttledSetScrollFade: throttle(this.setScrollFade, this.throttleDuration), + contentClientHeight: 0, + maxPosition: 0, + store: boardsStore, + filterTerm: '', + }; + }, + computed: { + currentPage() { + return this.state.currentPage; + }, + filteredBoards() { + return this.boards.filter(board => + board.name.toLowerCase().includes(this.filterTerm.toLowerCase()), + ); + }, + reload: { + get() { + return this.state.reload; + }, + set(newValue) { + this.state.reload = newValue; + }, + }, + board() { + return this.state.currentBoard; + }, + showDelete() { + return this.boards.length > 1; + }, + scrollFadeClass() { + return { + 'fade-out': !this.hasScrollFade, + }; + }, + showRecentSection() { + return ( + this.recentBoards.length && + this.boards.length > MIN_BOARDS_TO_VIEW_RECENT && + !this.filterTerm.length + ); + }, + }, + watch: { + filteredBoards() { + this.scrollFadeInitialized = false; + this.$nextTick(this.setScrollFade); + }, + reload() { + if (this.reload) { + this.boards = []; + this.recentBoards = []; + this.loading = true; + this.reload = false; + + this.loadBoards(false); + } + }, + }, + created() { + boardsStore.setCurrentBoard(this.currentBoard); + }, + methods: { + showPage(page) { + boardsStore.showPage(page); + }, + loadBoards(toggleDropdown = true) { + if (toggleDropdown && this.boards.length > 0) { + return; + } + + const recentBoardsPromise = new Promise((resolve, reject) => + gl.boardService + .recentBoards() + .then(resolve) + .catch(err => { + /** + * If user is unauthorized we'd still want to resolve the + * request to display all boards. + */ + if (err.response.status === httpStatusCodes.UNAUTHORIZED) { + resolve({ data: [] }); // recent boards are empty + return; + } + reject(err); + }), + ); + + Promise.all([gl.boardService.allBoards(), recentBoardsPromise]) + .then(([allBoards, recentBoards]) => [allBoards.data, recentBoards.data]) + .then(([allBoardsJson, recentBoardsJson]) => { + this.loading = false; + this.boards = allBoardsJson; + this.recentBoards = recentBoardsJson; + }) + .then(() => this.$nextTick()) // Wait for boards list in DOM + .then(() => { + this.setScrollFade(); + }) + .catch(() => { + this.loading = false; + }); + }, + isScrolledUp() { + const { content } = this.$refs; + const currentPosition = this.contentClientHeight + content.scrollTop; + + return content && currentPosition < this.maxPosition; + }, + initScrollFade() { + this.scrollFadeInitialized = true; + + const { content } = this.$refs; + + this.contentClientHeight = content.clientHeight; + this.maxPosition = content.scrollHeight; + }, + setScrollFade() { + if (!this.scrollFadeInitialized) this.initScrollFade(); + + this.hasScrollFade = this.isScrolledUp(); + }, + }, +}; +</script> + +<template> + <div class="boards-switcher js-boards-selector append-right-10"> + <span class="boards-selector-wrapper js-boards-selector-wrapper"> + <gl-dropdown + data-qa-selector="boards_dropdown" + toggle-class="dropdown-menu-toggle js-dropdown-toggle" + menu-class="flex-column dropdown-extended-height" + :text="board.name" + @show="loadBoards" + > + <div> + <div class="dropdown-title mb-0" @mousedown.prevent> + {{ s__('IssueBoards|Switch board') }} + </div> + </div> + + <gl-dropdown-header class="mt-0"> + <gl-search-box-by-type ref="searchBox" v-model="filterTerm" /> + </gl-dropdown-header> + + <div + v-if="!loading" + ref="content" + class="dropdown-content flex-fill" + @scroll.passive="throttledSetScrollFade" + > + <gl-dropdown-item + v-show="filteredBoards.length === 0" + class="no-pointer-events text-secondary" + > + {{ s__('IssueBoards|No matching boards found') }} + </gl-dropdown-item> + + <h6 v-if="showRecentSection" class="dropdown-bold-header my-0"> + {{ __('Recent') }} + </h6> + + <template v-if="showRecentSection"> + <gl-dropdown-item + v-for="recentBoard in recentBoards" + :key="`recent-${recentBoard.id}`" + class="js-dropdown-item" + :href="`${boardBaseUrl}/${recentBoard.id}`" + > + {{ recentBoard.name }} + </gl-dropdown-item> + </template> + + <hr v-if="showRecentSection" class="my-1" /> + + <h6 v-if="showRecentSection" class="dropdown-bold-header my-0"> + {{ __('All') }} + </h6> + + <gl-dropdown-item + v-for="otherBoard in filteredBoards" + :key="otherBoard.id" + class="js-dropdown-item" + :href="`${boardBaseUrl}/${otherBoard.id}`" + > + {{ otherBoard.name }} + </gl-dropdown-item> + <gl-dropdown-item v-if="hasMissingBoards" class="small unclickable"> + {{ + s__( + 'IssueBoards|Some of your boards are hidden, activate a license to see them again.', + ) + }} + </gl-dropdown-item> + </div> + + <div + v-show="filteredBoards.length > 0" + class="dropdown-content-faded-mask" + :class="scrollFadeClass" + ></div> + + <gl-loading-icon v-if="loading" /> + + <div v-if="canAdminBoard"> + <gl-dropdown-divider /> + + <gl-dropdown-item v-if="multipleIssueBoardsAvailable" @click.prevent="showPage('new')"> + {{ s__('IssueBoards|Create new board') }} + </gl-dropdown-item> + + <gl-dropdown-item + v-if="showDelete" + class="text-danger" + @click.prevent="showPage('delete')" + > + {{ s__('IssueBoards|Delete board') }} + </gl-dropdown-item> + </div> + </gl-dropdown> + + <board-form + v-if="currentPage" + :milestone-path="milestonePath" + :labels-path="labelsPath" + :project-id="projectId" + :group-id="groupId" + :can-admin-board="canAdminBoard" + :scoped-issue-board-feature-enabled="scopedIssueBoardFeatureEnabled" + :weights="weights" + :enable-scoped-labels="enabledScopedLabels" + :scoped-labels-documentation-link="scopedLabelsDocumentationLink" + /> + </span> + </div> +</template> diff --git a/app/assets/javascripts/boards/components/modal/footer.vue b/app/assets/javascripts/boards/components/modal/footer.vue index a1d634c8f19..5f100c617a0 100644 --- a/app/assets/javascripts/boards/components/modal/footer.vue +++ b/app/assets/javascripts/boards/components/modal/footer.vue @@ -1,4 +1,5 @@ <script> +import footerEEMixin from 'ee_else_ce/boards/mixins/modal_footer'; import Flash from '../../../flash'; import { __, n__ } from '../../../locale'; import ListsDropdown from './lists_dropdown.vue'; @@ -10,7 +11,7 @@ export default { components: { ListsDropdown, }, - mixins: [modalMixin], + mixins: [modalMixin, footerEEMixin], data() { return { modal: ModalStore.store, @@ -41,7 +42,7 @@ export default { const req = this.buildUpdateRequest(list); // Post the data to the backend - gl.boardService.bulkUpdate(issueIds, req).catch(() => { + boardsStore.bulkUpdate(issueIds, req).catch(() => { Flash(__('Failed to update issues, please try again.')); selectedIssues.forEach(issue => { diff --git a/app/assets/javascripts/boards/components/modal/header.vue b/app/assets/javascripts/boards/components/modal/header.vue index 7a696035dc8..8cd4840d3d6 100644 --- a/app/assets/javascripts/boards/components/modal/header.vue +++ b/app/assets/javascripts/boards/components/modal/header.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable @gitlab/vue-i18n/no-bare-strings */ import { __ } from '~/locale'; import ModalFilters from './filters'; import ModalTabs from './tabs.vue'; diff --git a/app/assets/javascripts/boards/components/modal/tabs.vue b/app/assets/javascripts/boards/components/modal/tabs.vue index 2d2920e312e..7430fc96654 100644 --- a/app/assets/javascripts/boards/components/modal/tabs.vue +++ b/app/assets/javascripts/boards/components/modal/tabs.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable @gitlab/vue-i18n/no-bare-strings */ import ModalStore from '../../stores/modal_store'; import modalMixin from '../../mixins/modal_mixins'; diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index a1cf1866faf..e8d25e84be1 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -68,13 +68,15 @@ export default { <li> <a href='#' class='dropdown-menu-link' data-project-id="${ project.id - }" data-project-name="${project.name}"> - ${_.escape(project.name)} + }" data-project-name="${project.name}" data-project-name-with-namespace="${ + project.name_with_namespace + }"> + ${_.escape(project.name_with_namespace)} </a> </li> `; }, - text: project => project.name, + text: project => project.name_with_namespace, }); }, }; diff --git a/app/assets/javascripts/boards/ee_functions.js b/app/assets/javascripts/boards/ee_functions.js new file mode 100644 index 00000000000..583270fcae5 --- /dev/null +++ b/app/assets/javascripts/boards/ee_functions.js @@ -0,0 +1,7 @@ +export const setPromotionState = () => {}; + +export const setWeigthFetchingState = () => {}; +export const setEpicFetchingState = () => {}; + +export const getMilestoneTitle = () => ({}); +export const getBoardsModalData = () => ({}); diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index d6a5372b22d..3bded4a3258 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -1,7 +1,6 @@ import $ from 'jquery'; import Vue from 'vue'; -import mountMultipleBoardsSwitcher from 'ee_else_ce/boards/mount_multiple_boards_switcher'; import Flash from '~/flash'; import { __ } from '~/locale'; import './models/label'; @@ -31,6 +30,14 @@ import { } from '~/lib/utils/common_utils'; import boardConfigToggle from 'ee_else_ce/boards/config_toggle'; import toggleFocusMode from 'ee_else_ce/boards/toggle_focus'; +import { + setPromotionState, + setWeigthFetchingState, + setEpicFetchingState, + getMilestoneTitle, + getBoardsModalData, +} from 'ee_else_ce/boards/ee_functions'; +import mountMultipleBoardsSwitcher from './mount_multiple_boards_switcher'; let issueBoardsApp; @@ -129,6 +136,7 @@ export default () => { }); boardsStore.addBlankState(); + setPromotionState(boardsStore); this.loading = false; }) .catch(() => { @@ -143,6 +151,8 @@ export default () => { const { sidebarInfoEndpoint } = newIssue; if (sidebarInfoEndpoint && newIssue.subscribed === undefined) { newIssue.setFetchingState('subscriptions', true); + setWeigthFetchingState(newIssue, true); + setEpicFetchingState(newIssue, true); BoardService.getIssueInfo(sidebarInfoEndpoint) .then(res => res.data) .then(data => { @@ -157,6 +167,8 @@ export default () => { } = convertObjectPropsToCamelCase(data); newIssue.setFetchingState('subscriptions', false); + setWeigthFetchingState(newIssue, false); + setEpicFetchingState(newIssue, false); newIssue.updateData({ humanTimeSpent: humanTotalTimeSpent, timeSpent: totalTimeSpent, @@ -169,6 +181,7 @@ export default () => { }) .catch(() => { newIssue.setFetchingState('subscriptions', false); + setWeigthFetchingState(newIssue, false); Flash(__('An error occurred while fetching sidebar data')); }); } @@ -203,6 +216,7 @@ export default () => { el: document.getElementById('js-add-list'), data: { filters: boardsStore.state.filters, + ...getMilestoneTitle($boardApp), }, mounted() { initNewListDropdown(); @@ -222,6 +236,7 @@ export default () => { return { modal: ModalStore.store, store: boardsStore.state, + ...getBoardsModalData($boardApp), canAdminList: this.$options.el.hasAttribute('data-can-admin-list'), }; }, @@ -285,6 +300,6 @@ export default () => { }); } - toggleFocusMode(ModalStore, boardsStore); + toggleFocusMode(ModalStore, boardsStore, $boardApp); mountMultipleBoardsSwitcher(); }; diff --git a/app/assets/javascripts/boards/mixins/modal_footer.js b/app/assets/javascripts/boards/mixins/modal_footer.js new file mode 100644 index 00000000000..ff8b4c56321 --- /dev/null +++ b/app/assets/javascripts/boards/mixins/modal_footer.js @@ -0,0 +1 @@ +export default {}; diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js index bdb14a7f2f2..8d22f009784 100644 --- a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js +++ b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js @@ -1,2 +1,35 @@ -// this will be moved from EE to CE as part of https://gitlab.com/gitlab-org/gitlab-ce/issues/53811 -export default () => {}; +import Vue from 'vue'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import BoardsSelector from '~/boards/components/boards_selector.vue'; + +export default () => { + const boardsSwitcherElement = document.getElementById('js-multiple-boards-switcher'); + return new Vue({ + el: boardsSwitcherElement, + components: { + BoardsSelector, + }, + 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: Number(dataset.projectId), + groupId: Number(dataset.groupId), + scopedIssueBoardFeatureEnabled: parseBoolean(dataset.scopedIssueBoardFeatureEnabled), + weights: JSON.parse(dataset.weights), + }; + + return { boardsSelectorProps }; + }, + render(createElement) { + return createElement(BoardsSelector, { + props: this.boardsSelectorProps, + }); + }, + }); +}; diff --git a/app/assets/javascripts/boards/services/board_service.js b/app/assets/javascripts/boards/services/board_service.js index 580d04a3649..56a6cab6c73 100644 --- a/app/assets/javascripts/boards/services/board_service.js +++ b/app/assets/javascripts/boards/services/board_service.js @@ -1,4 +1,9 @@ /* eslint-disable class-methods-use-this */ +/** + * This file is intended to be deleted. + * The existing functions will removed one by one in favor of using the board store directly. + * see https://gitlab.com/gitlab-org/gitlab-ce/issues/61621 + */ import boardsStore from '~/boards/stores/boards_store'; @@ -62,6 +67,22 @@ export default class BoardService { static toggleIssueSubscription(endpoint) { return boardsStore.toggleIssueSubscription(endpoint); } + + allBoards() { + return boardsStore.allBoards(); + } + + recentBoards() { + return boardsStore.recentBoards(); + } + + createBoard(board) { + return boardsStore.createBoard(board); + } + + deleteBoard({ id }) { + return boardsStore.deleteBoard({ id }); + } } window.BoardService = BoardService; diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index b9cd4a143ef..f57c684691c 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -340,6 +340,44 @@ const boardsStore = { toggleIssueSubscription(endpoint) { return axios.post(endpoint); }, + + allBoards() { + return axios.get(this.generateBoardsPath()); + }, + + recentBoards() { + return axios.get(this.state.endpoints.recentBoardsEndpoint); + }, + + createBoard(board) { + const boardPayload = { ...board }; + boardPayload.label_ids = (board.labels || []).map(b => b.id); + + if (boardPayload.label_ids.length === 0) { + boardPayload.label_ids = ['']; + } + + if (boardPayload.assignee) { + boardPayload.assignee_id = boardPayload.assignee.id; + } + + if (boardPayload.milestone) { + boardPayload.milestone_id = boardPayload.milestone.id; + } + + if (boardPayload.id) { + return axios.put(this.generateBoardsPath(boardPayload.id), { board: boardPayload }); + } + return axios.post(this.generateBoardsPath(), { board: boardPayload }); + }, + + deleteBoard({ id }) { + return axios.delete(this.generateBoardsPath(id)); + }, + + setCurrentBoard(board) { + this.state.currentBoard = board; + }, }; BoardsStoreEE.initEESpecific(boardsStore); |