diff options
Diffstat (limited to 'app/assets/javascripts/boards')
26 files changed, 160 insertions, 361 deletions
diff --git a/app/assets/javascripts/boards/boards_util.js b/app/assets/javascripts/boards/boards_util.js index 96cc774a280..9fca9860282 100644 --- a/app/assets/javascripts/boards/boards_util.js +++ b/app/assets/javascripts/boards/boards_util.js @@ -111,7 +111,7 @@ export function fullLabelId(label) { export function formatIssueInput(issueInput, boardConfig) { const { labelIds = [], assigneeIds = [] } = issueInput; - const { labels, assigneeId, milestoneId } = boardConfig; + const { labels, assigneeId, milestoneId, weight } = boardConfig; return { ...issueInput, @@ -121,6 +121,7 @@ export function formatIssueInput(issueInput, boardConfig) { : issueInput?.milestoneId, labelIds: [...labelIds, ...(labels?.map((l) => fullLabelId(l)) || [])], assigneeIds: [...assigneeIds, ...(assigneeId ? [fullUserId(assigneeId)] : [])], + weight: weight > -1 ? weight : undefined, }; } diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue index 28f4a267077..858aabb0f05 100644 --- a/app/assets/javascripts/boards/components/board_app.vue +++ b/app/assets/javascripts/boards/components/board_app.vue @@ -2,11 +2,13 @@ import { mapActions, mapGetters } from 'vuex'; 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'; export default { components: { BoardContent, BoardSettingsSidebar, + BoardTopBar, }, inject: ['disabled'], computed: { @@ -23,6 +25,7 @@ export default { <template> <div class="boards-app gl-relative" :class="{ 'is-compact': isSidebarOpen }"> + <board-top-bar /> <board-content :disabled="disabled" /> <board-settings-sidebar /> </div> diff --git a/app/assets/javascripts/boards/components/board_card_inner.vue b/app/assets/javascripts/boards/components/board_card_inner.vue index aee61a5b2a5..814ff16efec 100644 --- a/app/assets/javascripts/boards/components/board_card_inner.vue +++ b/app/assets/javascripts/boards/components/board_card_inner.vue @@ -13,7 +13,7 @@ import boardCardInner from 'ee_else_ce/boards/mixins/board_card_inner'; import { isScopedLabel } from '~/lib/utils/common_utils'; import { sprintf, __, n__ } from '~/locale'; import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; -import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue'; +import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue'; import { ListType } from '../constants'; import BoardBlockedIcon from './board_blocked_icon.vue'; import IssueDueDate from './issue_due_date.vue'; @@ -240,7 +240,7 @@ export default { class="board-card-footer gl-display-flex gl-justify-content-space-between gl-align-items-flex-end" > <div - class="gl-display-flex align-items-start flex-wrap-reverse board-card-number-container gl-overflow-hidden js-board-card-number-container" + class="gl-display-flex align-items-start flex-wrap-reverse board-card-number-container gl-overflow-hidden" > <gl-loading-icon v-if="item.isLoading" size="md" class="mt-3" /> <span diff --git a/app/assets/javascripts/boards/components/board_content.vue b/app/assets/javascripts/boards/components/board_content.vue index 27ea2e7a608..1d6a71aca47 100644 --- a/app/assets/javascripts/boards/components/board_content.vue +++ b/app/assets/javascripts/boards/components/board_content.vue @@ -4,7 +4,7 @@ import { sortBy } from 'lodash'; import Draggable from 'vuedraggable'; import { mapState, mapGetters, mapActions } from 'vuex'; import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue'; -import defaultSortableConfig from '~/sortable/sortable_config'; +import { defaultSortableOptions } from '~/sortable/constants'; import { DraggableItemTypes } from '../constants'; import BoardColumn from './board_column.vue'; @@ -43,7 +43,7 @@ export default { }, draggableOptions() { const options = { - ...defaultSortableConfig, + ...defaultSortableOptions, disabled: this.disabled, draggable: '.is-draggable', fallbackOnBody: false, diff --git a/app/assets/javascripts/boards/components/board_filtered_search.vue b/app/assets/javascripts/boards/components/board_filtered_search.vue index 95d4fd5bc0a..aeb2cee590d 100644 --- a/app/assets/javascripts/boards/components/board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/board_filtered_search.vue @@ -4,7 +4,10 @@ import { mapActions } from 'vuex'; import { getIdFromGraphQLId, isGid } 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'; +import { + FILTERED_SEARCH_TERM, + FILTER_ANY, +} 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'; @@ -42,6 +45,7 @@ export default { search, milestoneTitle, iterationId, + iterationCadenceId, types, weight, epicId, @@ -95,10 +99,20 @@ export default { }); } - if (iterationId) { + let iterationData = null; + + if (iterationId && iterationCadenceId) { + iterationData = `${iterationId}&${iterationCadenceId}`; + } else if (iterationCadenceId) { + iterationData = `${FILTER_ANY}&${iterationCadenceId}`; + } else if (iterationId) { + iterationData = iterationId; + } + + if (iterationData) { filteredSearchValue.push({ type: 'iteration', - value: { data: iterationId, operator: '=' }, + value: { data: iterationData, operator: '=' }, }); } @@ -228,9 +242,12 @@ export default { epicId, myReactionEmoji, iterationId, + iterationCadenceId, releaseTag, confidential, } = this.filterParams; + let iteration = iterationId; + let cadence = iterationCadenceId; let notParams = {}; if (Object.prototype.hasOwnProperty.call(this.filterParams, 'not')) { @@ -251,6 +268,10 @@ export default { ); } + if (iterationId?.includes('&')) { + [iteration, cadence] = iterationId.split('&'); + } + return mapValues( { ...notParams, @@ -259,7 +280,8 @@ export default { assignee_username: assigneeUsername, assignee_id: assigneeId, milestone_title: milestoneTitle, - iteration_id: iterationId, + iteration_id: iteration, + iteration_cadence_id: cadence, search, types, weight, diff --git a/app/assets/javascripts/boards/components/board_form.vue b/app/assets/javascripts/boards/components/board_form.vue index 5fcf9514708..a874c9e070a 100644 --- a/app/assets/javascripts/boards/components/board_form.vue +++ b/app/assets/javascripts/boards/components/board_form.vue @@ -48,7 +48,7 @@ export default { fullPath: { default: '', }, - rootPath: { + boardBaseUrl: { default: '', }, }, @@ -209,7 +209,7 @@ export default { if (this.isDeleteForm) { try { await this.deleteBoard(); - visitUrl(this.rootPath); + visitUrl(this.boardBaseUrl); } catch { this.setError({ message: this.$options.i18n.deleteErrorMessage }); } finally { @@ -289,7 +289,7 @@ export default { <p v-if="isDeleteForm" data-testid="delete-confirmation-message"> {{ $options.i18n.deleteConfirmationMessage }} </p> - <form v-else class="js-board-config-modal" data-testid="board-form-wrapper" @submit.prevent> + <form v-else data-testid="board-form-wrapper" @submit.prevent> <div v-if="!readonly" class="gl-mb-5" data-testid="board-form"> <label class="gl-font-weight-bold gl-font-lg" for="board-new-name"> {{ $options.i18n.titleFieldLabel }} diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 1024be61359..47f25f34d0c 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -2,9 +2,9 @@ import { GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui'; import Draggable from 'vuedraggable'; import { mapActions, mapGetters, mapState } from 'vuex'; -import { sortableStart, sortableEnd } from '~/boards/mixins/sortable_default_options'; import { sprintf, __ } from '~/locale'; -import defaultSortableConfig from '~/sortable/sortable_config'; +import { defaultSortableOptions } from '~/sortable/constants'; +import { sortableStart, sortableEnd } from '~/sortable/utils'; import Tracking from '~/tracking'; import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql'; import { toggleFormEventPrefix, DraggableItemTypes } from '../constants'; @@ -121,7 +121,7 @@ export default { }, treeRootOptions() { const options = { - ...defaultSortableConfig, + ...defaultSortableOptions, fallbackOnBody: false, group: 'board-list', tag: 'ul', @@ -287,7 +287,7 @@ export default { :data-board-type="list.listType" :class="{ 'bg-danger-100': boardItemsSizeExceedsMax }" draggable=".board-card" - class="board-list gl-w-full gl-h-full gl-list-style-none gl-mb-0 gl-p-2 js-board-list" + class="board-list gl-w-full gl-h-full gl-list-style-none gl-mb-0 gl-p-2" data-testid="tree-root-wrapper" @start="handleDragOnStart" @end="handleDragOnEnd" diff --git a/app/assets/javascripts/boards/components/board_list_header.vue b/app/assets/javascripts/boards/components/board_list_header.vue index 46b28d20da9..9f70c84931f 100644 --- a/app/assets/javascripts/boards/components/board_list_header.vue +++ b/app/assets/javascripts/boards/components/board_list_header.vue @@ -18,7 +18,7 @@ import Tracking from '~/tracking'; import { formatDate } from '~/lib/utils/datetime_utility'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import listQuery from 'ee_else_ce/boards/graphql/board_lists_deferred.query.graphql'; -import AccessorUtilities from '../../lib/utils/accessor'; +import AccessorUtilities from '~/lib/utils/accessor'; import { inactiveId, LIST, ListType, toggleFormEventPrefix } from '../constants'; import eventHub from '../eventhub'; import ItemCount from './item_count.vue'; @@ -57,6 +57,9 @@ export default { currentUserId: { default: null, }, + canCreateEpic: { + default: false, + }, }, props: { list: { @@ -129,7 +132,7 @@ export default { return (this.listType === ListType.backlog || this.showListHeaderButton) && !this.isEpicBoard; }, isNewEpicShown() { - return this.isEpicBoard && this.listType !== ListType.closed; + return this.isEpicBoard && this.canCreateEpic && this.listType !== ListType.closed; }, isSettingsShown() { return ( @@ -262,7 +265,7 @@ export default { 'gl-py-2': list.collapsed && isSwimlanesHeader, 'gl-flex-direction-column': list.collapsed, }" - class="board-title gl-m-0 gl-display-flex gl-align-items-center gl-font-base gl-px-3 js-board-handle" + class="board-title gl-m-0 gl-display-flex gl-align-items-center gl-font-base gl-px-3" > <gl-button v-gl-tooltip.hover @@ -443,12 +446,11 @@ export default { ref="settingsBtn" v-gl-tooltip.hover :aria-label="$options.i18n.listSettings" - class="no-drag js-board-settings-button" + class="no-drag" :title="$options.i18n.listSettings" icon="settings" @click="openSidebarSettings" /> - <gl-tooltip :target="() => $refs.settingsBtn">{{ $options.i18n.listSettings }}</gl-tooltip> </gl-button-group> </h3> </header> diff --git a/app/assets/javascripts/boards/components/board_top_bar.vue b/app/assets/javascripts/boards/components/board_top_bar.vue new file mode 100644 index 00000000000..f90ac1e9079 --- /dev/null +++ b/app/assets/javascripts/boards/components/board_top_bar.vue @@ -0,0 +1,54 @@ +<script> +import { mapGetters } from 'vuex'; +import BoardAddNewColumnTrigger from '~/boards/components/board_add_new_column_trigger.vue'; +import BoardsSelector from 'ee_else_ce/boards/components/boards_selector.vue'; +import IssueBoardFilteredSearch from 'ee_else_ce/boards/components/issue_board_filtered_search.vue'; +import ConfigToggle from './config_toggle.vue'; +import NewBoardButton from './new_board_button.vue'; +import ToggleFocus from './toggle_focus.vue'; + +export default { + components: { + BoardAddNewColumnTrigger, + BoardsSelector, + IssueBoardFilteredSearch, + ConfigToggle, + NewBoardButton, + ToggleFocus, + ToggleLabels: () => import('ee_component/boards/components/toggle_labels.vue'), + ToggleEpicsSwimlanes: () => import('ee_component/boards/components/toggle_epics_swimlanes.vue'), + EpicBoardFilteredSearch: () => + import('ee_component/boards/components/epic_filtered_search.vue'), + }, + inject: ['swimlanesFeatureAvailable', 'canAdminList', 'isSignedIn'], + computed: { + ...mapGetters(['isEpicBoard']), + }, +}; +</script> + +<template> + <div class="issues-filters"> + <div + class="issues-details-filters filtered-search-block gl-display-flex gl-flex-direction-column gl-lg-flex-direction-row row-content-block second-block" + > + <div + class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-flex-grow-1 gl-lg-mb-0! mb-md-2 mb-sm-0 gl-w-full" + > + <boards-selector /> + <new-board-button /> + <epic-board-filtered-search v-if="isEpicBoard" /> + <issue-board-filtered-search v-else /> + </div> + <div + class="filter-dropdown-container gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-align-items-flex-start" + > + <toggle-labels /> + <toggle-epics-swimlanes v-if="swimlanesFeatureAvailable && isSignedIn" /> + <config-toggle /> + <board-add-new-column-trigger v-if="canAdminList" /> + <toggle-focus /> + </div> + </div> + </div> +</template> diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue index 91fdfd668fc..2951eda1112 100644 --- a/app/assets/javascripts/boards/components/boards_selector.vue +++ b/app/assets/javascripts/boards/components/boards_selector.vue @@ -40,37 +40,21 @@ export default { directives: { GlModalDirective, }, - inject: ['fullPath'], + inject: [ + 'boardBaseUrl', + 'fullPath', + 'canAdminBoard', + 'multipleIssueBoardsAvailable', + 'hasMissingBoards', + 'scopedIssueBoardFeatureEnabled', + 'weights', + ], props: { throttleDuration: { type: Number, default: 200, required: false, }, - boardBaseUrl: { - type: String, - required: true, - }, - hasMissingBoards: { - type: Boolean, - required: true, - }, - canAdminBoard: { - type: Boolean, - required: true, - }, - multipleIssueBoardsAvailable: { - type: Boolean, - required: true, - }, - scopedIssueBoardFeatureEnabled: { - type: Boolean, - required: true, - }, - weights: { - type: Array, - required: true, - }, }, data() { return { @@ -255,11 +239,12 @@ export default { </script> <template> - <div class="boards-switcher js-boards-selector gl-mr-3"> - <span class="boards-selector-wrapper js-boards-selector-wrapper"> + <div class="boards-switcher gl-mr-3" data-testid="boards-selector"> + <span class="boards-selector-wrapper"> <gl-dropdown + data-testid="boards-dropdown" data-qa-selector="boards_dropdown" - toggle-class="dropdown-menu-toggle js-dropdown-toggle" + toggle-class="dropdown-menu-toggle" menu-class="flex-column dropdown-extended-height" :loading="isBoardLoading" :text="board.name" @@ -292,8 +277,8 @@ export default { <gl-dropdown-item v-for="recentBoard in recentBoards" :key="`recent-${recentBoard.id}`" - class="js-dropdown-item" :href="`${boardBaseUrl}/${recentBoard.id}`" + data-testid="dropdown-item" > {{ recentBoard.name }} </gl-dropdown-item> @@ -308,8 +293,8 @@ export default { <gl-dropdown-item v-for="otherBoard in filteredBoards" :key="otherBoard.id" - class="js-dropdown-item" :href="`${boardBaseUrl}/${otherBoard.id}`" + data-testid="dropdown-item" > {{ otherBoard.name }} </gl-dropdown-item> @@ -347,7 +332,7 @@ export default { <gl-dropdown-item v-if="showDelete" v-gl-modal-directive="'board-config-modal'" - class="text-danger js-delete-board" + class="text-danger" @click.prevent="showPage('delete')" > {{ s__('IssueBoards|Delete board') }} diff --git a/app/assets/javascripts/boards/components/config_toggle.vue b/app/assets/javascripts/boards/components/config_toggle.vue index f39e4d90357..4746f598ab7 100644 --- a/app/assets/javascripts/boards/components/config_toggle.vue +++ b/app/assets/javascripts/boards/components/config_toggle.vue @@ -14,16 +14,7 @@ export default { GlModalDirective, }, mixins: [Tracking.mixin()], - props: { - canAdminList: { - type: Boolean, - required: true, - }, - hasScope: { - type: Boolean, - required: true, - }, - }, + inject: ['canAdminList', 'hasScope'], computed: { buttonText() { return this.canAdminList ? s__('Boards|Edit board') : s__('Boards|View scope'); diff --git a/app/assets/javascripts/boards/components/issuable_title.vue b/app/assets/javascripts/boards/components/issuable_title.vue deleted file mode 100644 index 40627a9fab8..00000000000 --- a/app/assets/javascripts/boards/components/issuable_title.vue +++ /dev/null @@ -1,21 +0,0 @@ -<script> -export default { - props: { - title: { - type: String, - required: true, - }, - refPath: { - type: String, - required: true, - }, - }, -}; -</script> - -<template> - <div data-testid="issue-title"> - <p class="gl-font-weight-bold">{{ title }}</p> - <p class="gl-mb-0">{{ refPath }}</p> - </div> -</template> 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 6bfdbb674a2..bab6fe26978 100644 --- a/app/assets/javascripts/boards/components/issue_board_filtered_search.vue +++ b/app/assets/javascripts/boards/components/issue_board_filtered_search.vue @@ -41,17 +41,7 @@ export default { confidential: __('Confidential'), }, components: { BoardFilteredSearch }, - inject: ['isSignedIn', 'releasesFetchPath'], - props: { - fullPath: { - type: String, - required: true, - }, - boardType: { - type: String, - required: true, - }, - }, + inject: ['isSignedIn', 'releasesFetchPath', 'fullPath', 'boardType'], computed: { isGroupBoard() { return this.boardType === BoardType.group; diff --git a/app/assets/javascripts/boards/components/issue_time_estimate.vue b/app/assets/javascripts/boards/components/issue_time_estimate.vue index 1ab7deebfaf..9312db06efe 100644 --- a/app/assets/javascripts/boards/components/issue_time_estimate.vue +++ b/app/assets/javascripts/boards/components/issue_time_estimate.vue @@ -43,7 +43,7 @@ export default { <gl-tooltip :target="() => $refs.issueTimeEstimate" placement="bottom" - class="js-issue-time-estimate" + data-testid="issue-time-estimate" > <span class="gl-font-weight-bold gl-display-block">{{ $options.i18n.timeEstimate }}</span> {{ title }} diff --git a/app/assets/javascripts/boards/components/item_count.vue b/app/assets/javascripts/boards/components/item_count.vue index 9b1ff254766..a11c23e5625 100644 --- a/app/assets/javascripts/boards/components/item_count.vue +++ b/app/assets/javascripts/boards/components/item_count.vue @@ -29,7 +29,7 @@ export default { <span :class="{ 'text-danger': issuesExceedMax }" data-testid="board-items-count"> {{ itemsSize }} </span> - <span v-if="isMaxLimitSet" class="js-max-issue-size"> + <span v-if="isMaxLimitSet" class="max-issue-size"> {{ maxIssueCount }} </span> </div> diff --git a/app/assets/javascripts/boards/components/toggle_focus.vue b/app/assets/javascripts/boards/components/toggle_focus.vue index 49f5e7d20a9..71612e0742f 100644 --- a/app/assets/javascripts/boards/components/toggle_focus.vue +++ b/app/assets/javascripts/boards/components/toggle_focus.vue @@ -10,12 +10,6 @@ export default { directives: { GlTooltip, }, - props: { - issueBoardsContentSelector: { - type: String, - required: true, - }, - }, data() { return { isFullscreen: false, @@ -25,7 +19,7 @@ export default { toggleFocusMode() { hide(this.$refs.toggleFocusModeButton); - const issueBoardsContent = document.querySelector(this.issueBoardsContentSelector); + const issueBoardsContent = document.querySelector('.content-wrapper > .js-focus-mode-board'); issueBoardsContent.classList.toggle('is-focused'); this.isFullscreen = !this.isFullscreen; @@ -44,7 +38,6 @@ export default { v-gl-tooltip category="tertiary" :icon="isFullscreen ? 'minimize' : 'maximize'" - class="js-focus-mode-btn" data-qa-selector="focus_mode_button" :title="$options.i18n.toggleFocusMode" :aria-label="$options.i18n.toggleFocusMode" diff --git a/app/assets/javascripts/boards/config_toggle.js b/app/assets/javascripts/boards/config_toggle.js deleted file mode 100644 index 1e54c2511b8..00000000000 --- a/app/assets/javascripts/boards/config_toggle.js +++ /dev/null @@ -1,25 +0,0 @@ -import Vue from 'vue'; -import { parseBoolean } from '~/lib/utils/common_utils'; -import ConfigToggle from './components/config_toggle.vue'; - -export default () => { - const el = document.querySelector('.js-board-config'); - - if (!el) { - return; - } - - // eslint-disable-next-line no-new - new Vue({ - el, - name: 'ConfigToggleRoot', - render(h) { - return h(ConfigToggle, { - props: { - canAdminList: parseBoolean(el.dataset.canAdminList), - hasScope: parseBoolean(el.dataset.hasScope), - }, - }); - }, - }); -}; diff --git a/app/assets/javascripts/boards/graphql/group_projects.query.graphql b/app/assets/javascripts/boards/graphql/group_projects.query.graphql index 0da14d0b872..e0a3cb0ee21 100644 --- a/app/assets/javascripts/boards/graphql/group_projects.query.graphql +++ b/app/assets/javascripts/boards/graphql/group_projects.query.graphql @@ -1,4 +1,4 @@ -#import "~/graphql_shared/fragments/pageInfo.fragment.graphql" +#import "~/graphql_shared/fragments/page_info.fragment.graphql" query boardsGetGroupProjects($fullPath: ID!, $search: String, $after: String) { group(fullPath: $fullPath) { diff --git a/app/assets/javascripts/boards/index.js b/app/assets/javascripts/boards/index.js index b31b56e6839..77c5994b5a1 100644 --- a/app/assets/javascripts/boards/index.js +++ b/app/assets/javascripts/boards/index.js @@ -1,22 +1,19 @@ import PortalVue from 'portal-vue'; import Vue from 'vue'; import VueApollo from 'vue-apollo'; - -import toggleEpicsSwimlanes from 'ee_else_ce/boards/toggle_epics_swimlanes'; -import toggleLabels from 'ee_else_ce/boards/toggle_labels'; -import BoardAddNewColumnTrigger from '~/boards/components/board_add_new_column_trigger.vue'; import BoardApp from '~/boards/components/board_app.vue'; import '~/boards/filters/due_date_filters'; import { issuableTypes } from '~/boards/constants'; -import initBoardsFilteredSearch from '~/boards/mount_filtered_search_issue_boards'; import store from '~/boards/stores'; -import toggleFocusMode from '~/boards/toggle_focus'; -import { NavigationType, isLoggedIn, parseBoolean } from '~/lib/utils/common_utils'; +import { + NavigationType, + isLoggedIn, + parseBoolean, + convertObjectPropsToCamelCase, +} from '~/lib/utils/common_utils'; +import { queryToObject } from '~/lib/utils/url_utility'; 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'; Vue.use(VueApollo); Vue.use(PortalVue); @@ -28,6 +25,12 @@ const apolloProvider = new VueApollo({ function mountBoardApp(el) { const { boardId, groupId, fullPath, rootPath } = el.dataset; + const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true }); + + const initialFilterParams = { + ...convertObjectPropsToCamelCase(rawFilterParams), + }; + store.dispatch('fetchBoard', { fullPath, fullBoardId: fullBoardId(boardId), @@ -54,26 +57,41 @@ function mountBoardApp(el) { boardId, groupId: Number(groupId), rootPath, + fullPath, + initialFilterParams, + boardBaseUrl: el.dataset.boardBaseUrl, + boardType: el.dataset.parent, currentUserId: gon.current_user_id || null, - canUpdate: parseBoolean(el.dataset.canUpdate), - canAdminList: parseBoolean(el.dataset.canAdminList), + boardWeight: el.dataset.boardWeight ? parseInt(el.dataset.boardWeight, 10) : null, labelsManagePath: el.dataset.labelsManagePath, labelsFilterBasePath: el.dataset.labelsFilterBasePath, + releasesFetchPath: el.dataset.releasesFetchPath, timeTrackingLimitToHours: parseBoolean(el.dataset.timeTrackingLimitToHours), + issuableType: issuableTypes.issue, + emailsDisabled: parseBoolean(el.dataset.emailsDisabled), + hasScope: parseBoolean(el.dataset.hasScope), + hasMissingBoards: parseBoolean(el.dataset.hasMissingBoards), + weights: el.dataset.weights ? JSON.parse(el.dataset.weights) : [], + // Permissions + canUpdate: parseBoolean(el.dataset.canUpdate), + canAdminList: parseBoolean(el.dataset.canAdminList), + canAdminBoard: parseBoolean(el.dataset.canAdminBoard), + allowLabelCreate: parseBoolean(el.dataset.canUpdate), + allowLabelEdit: parseBoolean(el.dataset.canUpdate), + isSignedIn: isLoggedIn(), + // Features multipleAssigneesFeatureAvailable: parseBoolean(el.dataset.multipleAssigneesFeatureAvailable), epicFeatureAvailable: parseBoolean(el.dataset.epicFeatureAvailable), iterationFeatureAvailable: parseBoolean(el.dataset.iterationFeatureAvailable), weightFeatureAvailable: parseBoolean(el.dataset.weightFeatureAvailable), - boardWeight: el.dataset.boardWeight ? parseInt(el.dataset.boardWeight, 10) : null, scopedLabelsAvailable: parseBoolean(el.dataset.scopedLabels), milestoneListsAvailable: parseBoolean(el.dataset.milestoneListsAvailable), assigneeListsAvailable: parseBoolean(el.dataset.assigneeListsAvailable), iterationListsAvailable: parseBoolean(el.dataset.iterationListsAvailable), - issuableType: issuableTypes.issue, - emailsDisabled: parseBoolean(el.dataset.emailsDisabled), - allowLabelCreate: parseBoolean(el.dataset.canUpdate), - allowLabelEdit: parseBoolean(el.dataset.canUpdate), allowScopedLabels: parseBoolean(el.dataset.scopedLabels), + swimlanesFeatureAvailable: gon.licensed_features?.swimlanes, + multipleIssueBoardsAvailable: parseBoolean(el.dataset.multipleBoardsAvailable), + scopedIssueBoardFeatureEnabled: parseBoolean(el.dataset.scopedIssueBoardFeatureEnabled), }, render: (createComponent) => createComponent(BoardApp), }); @@ -92,47 +110,5 @@ export default () => { } }); - const { releasesFetchPath, epicFeatureAvailable, iterationFeatureAvailable } = $boardApp.dataset; - initBoardsFilteredSearch( - apolloProvider, - isLoggedIn(), - releasesFetchPath, - parseBoolean(epicFeatureAvailable), - parseBoolean(iterationFeatureAvailable), - ); - mountBoardApp($boardApp); - - const createColumnTriggerEl = document.querySelector('.js-create-column-trigger'); - if (createColumnTriggerEl) { - // eslint-disable-next-line no-new - new Vue({ - el: createColumnTriggerEl, - name: 'BoardAddNewColumnTriggerRoot', - components: { - BoardAddNewColumnTrigger, - }, - store, - render(createElement) { - return createElement('board-add-new-column-trigger'); - }, - }); - } - - boardConfigToggle(); - initNewBoard(); - - toggleFocusMode(); - toggleLabels(); - - if (gon.licensed_features?.swimlanes) { - toggleEpicsSwimlanes(); - } - - mountMultipleBoardsSwitcher({ - fullPath: $boardApp.dataset.fullPath, - rootPath: $boardApp.dataset.boardsEndpoint, - allowScopedLabels: $boardApp.dataset.scopedLabels, - labelsManagePath: $boardApp.dataset.labelsManagePath, - }); }; diff --git a/app/assets/javascripts/boards/mixins/sortable_default_options.js b/app/assets/javascripts/boards/mixins/sortable_default_options.js deleted file mode 100644 index 1bb0ee5b7e3..00000000000 --- a/app/assets/javascripts/boards/mixins/sortable_default_options.js +++ /dev/null @@ -1,31 +0,0 @@ -/* global DocumentTouch */ - -import sortableConfig from '~/sortable/sortable_config'; - -export function sortableStart() { - document.body.classList.add('is-dragging'); -} - -export function sortableEnd() { - document.body.classList.remove('is-dragging'); -} - -export function getBoardSortableDefaultOptions(obj) { - const touchEnabled = - 'ontouchstart' in window || (window.DocumentTouch && document instanceof DocumentTouch); - - const defaultSortOptions = { - ...sortableConfig, - filter: '.no-drag', - delay: touchEnabled ? 100 : 0, - scrollSensitivity: touchEnabled ? 60 : 100, - scrollSpeed: 20, - onStart: sortableStart, - onEnd: sortableEnd, - }; - - Object.keys(obj).forEach((key) => { - defaultSortOptions[key] = obj[key]; - }); - return defaultSortOptions; -} diff --git a/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js b/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js deleted file mode 100644 index bb659eb075a..00000000000 --- a/app/assets/javascripts/boards/mount_filtered_search_issue_boards.js +++ /dev/null @@ -1,42 +0,0 @@ -import Vue from '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, - isSignedIn, - releasesFetchPath, - epicFeatureAvailable, - iterationFeatureAvailable, -) => { - const el = document.getElementById('js-issue-board-filtered-search'); - const rawFilterParams = queryToObject(window.location.search, { gatherArrays: true }); - - const initialFilterParams = { - ...convertObjectPropsToCamelCase(rawFilterParams, {}), - }; - - if (!el) { - return null; - } - - return new Vue({ - el, - name: 'BoardFilteredSearchRoot', - provide: { - initialFilterParams, - isSignedIn, - releasesFetchPath, - epicFeatureAvailable, - iterationFeatureAvailable, - }, - store, // TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/324094 - apolloProvider, - render: (createElement) => - createElement(IssueBoardFilteredSearch, { - props: { fullPath: store.state?.fullPath || '', boardType: store.state?.boardType || '' }, - }), - }); -}; diff --git a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js b/app/assets/javascripts/boards/mount_multiple_boards_switcher.js deleted file mode 100644 index 0bc9cfbd867..00000000000 --- a/app/assets/javascripts/boards/mount_multiple_boards_switcher.js +++ /dev/null @@ -1,50 +0,0 @@ -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'; - -Vue.use(VueApollo); - -const apolloProvider = new VueApollo({ - defaultClient: createDefaultClient(), -}); - -export default (params = {}) => { - const boardsSwitcherElement = document.getElementById('js-multiple-boards-switcher'); - const { dataset } = boardsSwitcherElement; - return new Vue({ - el: boardsSwitcherElement, - name: 'BoardsSelectorRoot', - components: { - BoardsSelector, - }, - apolloProvider, - store, - provide: { - fullPath: params.fullPath, - rootPath: params.rootPath, - allowScopedLabels: params.allowScopedLabels, - labelsManagePath: params.labelsManagePath, - allowLabelCreate: parseBoolean(dataset.canAdminBoard), - }, - data() { - const boardsSelectorProps = { - ...dataset, - hasMissingBoards: parseBoolean(dataset.hasMissingBoards), - canAdminBoard: parseBoolean(dataset.canAdminBoard), - multipleIssueBoardsAvailable: parseBoolean(dataset.multipleIssueBoardsAvailable), - 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/new_board.js b/app/assets/javascripts/boards/new_board.js deleted file mode 100644 index 34f2fea79a9..00000000000 --- a/app/assets/javascripts/boards/new_board.js +++ /dev/null @@ -1,29 +0,0 @@ -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/toggle_epics_swimlanes.js b/app/assets/javascripts/boards/toggle_epics_swimlanes.js deleted file mode 100644 index 2d1ec238274..00000000000 --- a/app/assets/javascripts/boards/toggle_epics_swimlanes.js +++ /dev/null @@ -1 +0,0 @@ -export default () => {}; diff --git a/app/assets/javascripts/boards/toggle_focus.js b/app/assets/javascripts/boards/toggle_focus.js deleted file mode 100644 index 8f057e192dd..00000000000 --- a/app/assets/javascripts/boards/toggle_focus.js +++ /dev/null @@ -1,18 +0,0 @@ -import Vue from 'vue'; -import ToggleFocus from './components/toggle_focus.vue'; - -export default () => { - const issueBoardsContentSelector = '.content-wrapper > .js-focus-mode-board'; - - return new Vue({ - el: '#js-toggle-focus-btn', - name: 'ToggleFocusRoot', - render(h) { - return h(ToggleFocus, { - props: { - issueBoardsContentSelector, - }, - }); - }, - }); -}; diff --git a/app/assets/javascripts/boards/toggle_labels.js b/app/assets/javascripts/boards/toggle_labels.js deleted file mode 100644 index 2d1ec238274..00000000000 --- a/app/assets/javascripts/boards/toggle_labels.js +++ /dev/null @@ -1 +0,0 @@ -export default () => {}; |