diff --git a/app/assets/javascripts/flash.js b/app/assets/javascripts/flash.js index c9b6a4f9913..5a47e76d597 100644 --- a/app/assets/javascripts/flash.js +++ b/app/assets/javascripts/flash.js @@ -86,48 +86,43 @@ const addDismissFlashClickListener = (flashEl, fadeTransition) => { /** * Render an alert at the top of the page, or, optionally an - * arbitrary existing container. - * - * This alert is always dismissible. - * - * Usage: - * - * 1. Render a new alert + * arbitrary existing container. This alert is always dismissible. * + * @example + * // Render a new alert * import { createAlert, VARIANT_WARNING } from '~/flash'; * * createAlert({ message: 'My error message' }); * createAlert({ message: 'My warning message', variant: VARIANT_WARNING }); * - * 2. Dismiss this alert programmatically - * + * @example + * // Dismiss this alert programmatically * const alert = createAlert({ message: 'Message' }); * * // ... * * alert.dismiss(); * - * 3. Respond to the alert being dismissed + * @example + * // Respond to the alert being dismissed + * createAlert({ message: 'Message', onDismiss: () => {} }); * - * createAlert({ message: 'Message', onDismiss: () => { ... }}); - * - * @param {Object} options Options to control the flash message - * @param {String} options.message Alert message text - * @param {String?} options.variant Which GlAlert variant to use, should be VARIANT_SUCCESS, VARIANT_WARNING, VARIANT_DANGER, VARIANT_INFO or VARIANT_TIP. Defaults to VARIANT_DANGER. - * @param {Object?} options.parent Reference to parent element under which alert needs to appear. Defaults to `document`. - * @param {Function?} options.onDismiss Handler to call when this alert is dismissed. - * @param {Object?} options.containerSelector Selector for the container of the alert - * @param {Object?} options.primaryButton Object describing primary button of alert - * @param {String?} link Href of primary button - * @param {String?} text Text of primary button - * @param {Function?} clickHandler Handler to call when primary button is clicked on. The click event is sent as an argument. - * @param {Object?} options.secondaryButton Object describing secondary button of alert - * @param {String?} link Href of secondary button - * @param {String?} text Text of secondary button - * @param {Function?} clickHandler Handler to call when secondary button is clicked on. The click event is sent as an argument. - * @param {Boolean?} options.captureError Whether to send error to Sentry - * @param {Object} options.error Error to be captured in Sentry - * @returns + * @param {object} options - Options to control the flash message + * @param {string} options.message - Alert message text + * @param {VARIANT_SUCCESS|VARIANT_WARNING|VARIANT_DANGER|VARIANT_INFO|VARIANT_TIP} [options.variant] - Which GlAlert variant to use; it defaults to VARIANT_DANGER. + * @param {object} [options.parent] - Reference to parent element under which alert needs to appear. Defaults to `document`. + * @param {Function} [options.onDismiss] - Handler to call when this alert is dismissed. + * @param {string} [options.containerSelector] - Selector for the container of the alert + * @param {object} [options.primaryButton] - Object describing primary button of alert + * @param {string} [options.primaryButton.link] - Href of primary button + * @param {string} [options.primaryButton.text] - Text of primary button + * @param {Function} [options.primaryButton.clickHandler] - Handler to call when primary button is clicked on. The click event is sent as an argument. + * @param {object} [options.secondaryButton] - Object describing secondary button of alert + * @param {string} [options.secondaryButton.link] - Href of secondary button + * @param {string} [options.secondaryButton.text] - Text of secondary button + * @param {Function} [options.secondaryButton.clickHandler] - Handler to call when secondary button is clicked on. The click event is sent as an argument. + * @param {boolean} [options.captureError] - Whether to send error to Sentry + * @param {object} [options.error] - Error to be captured in Sentry */ const createAlert = function createAlert({ message, @@ -208,22 +203,24 @@ const createAlert = function createAlert({ }; /** - * Flash banner supports different types of Flash configurations - * along with ability to provide actionConfig which can be used to show - * additional action or link on banner next to message + * @deprecated use `createAlert` instead * - * @param {Object} options Options to control the flash message - * @param {String} options.message Flash message text - * @param {String} options.type Type of Flash, it can be `notice`, `success`, `warning` or `alert` (default) - * @param {Object} options.parent Reference to parent element under which Flash needs to appear - * @param {Object} options.actionConfig Map of config to show action on banner - * @param {String} href URL to which action config should point to (default: '#') - * @param {String} title Title of action - * @param {Function} clickHandler Method to call when action is clicked on - * @param {Boolean} options.fadeTransition Boolean to determine whether to fade the alert out - * @param {Boolean} options.captureError Boolean to determine whether to send error to Sentry - * @param {Object} options.error Error to be captured in Sentry - * @deprecated Use `createAlert` instead. See https://gitlab.com/gitlab-org/gitlab/-/issues/362334. + * Flash banner supports different types of Flash configurations + * along with ability to provide actionConfig which can be used to show + * additional action or link on banner next to message + * + * @param {object} options - Options to control the flash message + * @param {string} options.message - Flash message text + * @param {'alert'|'notice'|'success'|'warning'} [options.type] - Type of Flash; it defaults to 'alert' + * @param {Element|Document} [options.parent] - Reference to parent element under which Flash needs to appear + * @param {object} [options.actionConfig] - Map of config to show action on banner + * @param {string} [options.actionConfig.href] - URL to which action config should point to (default: '#') + * @param {string} [options.actionConfig.title] - Title of action + * @param {Function} [options.actionConfig.clickHandler] - Method to call when action is clicked on + * @param {boolean} [options.fadeTransition] - Boolean to determine whether to fade the alert out + * @param {boolean} [options.addBodyClass] - Adds `flash-shown` class to the `body` element + * @param {boolean} [options.captureError] - Boolean to determine whether to send error to Sentry + * @param {object} [options.error] - Error to be captured in Sentry */ const createFlash = function createFlash({ message, diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 4101b520e80..2f3cdc525a7 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -195,7 +195,11 @@ $body.on('click', 'a[href^="#"]', function clickHashLinkCallback() { * Quick fix: Get rid of jQuery for this implementation */ const isBoardsPage = /(projects|groups):boards:show/.test(document.body.dataset.page); -if (!isBoardsPage && (bootstrapBreakpoint === 'sm' || bootstrapBreakpoint === 'xs')) { +if ( + !isBoardsPage && + !window.gon?.features?.movedMrSidebar && + (bootstrapBreakpoint === 'sm' || bootstrapBreakpoint === 'xs') +) { const $rightSidebar = $('aside.right-sidebar'); const $layoutPage = $('.layout-page'); diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 61f7a079d77..e02109d1fd1 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -1,5 +1,4 @@ /* eslint-disable no-new, class-methods-use-this */ -import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils'; import $ from 'jquery'; import Vue from 'vue'; import { getCookie, isMetaClick, parseBoolean, scrollToElement } from '~/lib/utils/common_utils'; @@ -176,6 +175,8 @@ export default class MergeRequestTabs { : null; this.navbar = document.querySelector('.navbar-gitlab'); this.peek = document.getElementById('js-peek'); + this.sidebar = document.querySelector('.js-right-sidebar'); + this.pageLayout = document.querySelector('.layout-page'); this.paddingTop = 16; this.scrollPositions = {}; @@ -282,7 +283,7 @@ export default class MergeRequestTabs { if (action === 'commits') { this.loadCommits(href); - this.expandView(); + // this.hideSidebar(); this.resetViewContainer(); this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable); } else if (action === 'new') { @@ -301,13 +302,12 @@ export default class MergeRequestTabs { */ this.loadDiff(href); } - if (bp.getBreakpointSize() !== 'xl') { - this.shrinkView(); - } + // this.hideSidebar(); this.expandViewContainer(); this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable); this.commitsTab.classList.remove('active'); } else if (action === 'pipelines') { + // this.hideSidebar(); this.resetViewContainer(); this.mountPipelinesView(); } else { @@ -320,9 +320,7 @@ export default class MergeRequestTabs { notesTab.classList.add('active'); } - if (bp.getBreakpointSize() !== 'xs') { - this.expandView(); - } + // this.showSidebar(); this.resetViewContainer(); this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable); } @@ -509,19 +507,6 @@ export default class MergeRequestTabs { } } - shrinkView() { - const $gutterBtn = $('.js-sidebar-toggle:visible'); - const $expandSvg = $gutterBtn.find('.js-sidebar-expand'); - - // Wait until listeners are set - setTimeout(() => { - // Only when sidebar is expanded - if ($expandSvg.length && $expandSvg.hasClass('hidden')) { - $gutterBtn.trigger('click', [true]); - } - }, 0); - } - // Expand the issuable sidebar unless the user explicitly collapsed it expandView() { if (parseBoolean(getCookie('collapsed_gutter'))) { @@ -538,4 +523,24 @@ export default class MergeRequestTabs { } }, 0); } + + hideSidebar() { + if (!isInVueNoteablePage() || this.cachedPageLayoutClasses) return; + + this.cachedPageLayoutClasses = this.pageLayout.className; + this.pageLayout.classList.remove( + 'right-sidebar-collapsed', + 'right-sidebar-expanded', + 'page-with-icon-sidebar', + ); + this.sidebar.style.width = '0px'; + } + + showSidebar() { + if (!isInVueNoteablePage() || !this.cachedPageLayoutClasses) return; + + this.pageLayout.className = this.cachedPageLayoutClasses; + this.sidebar.style.width = ''; + delete this.cachedPageLayoutClasses; + } } diff --git a/app/assets/javascripts/right_sidebar.js b/app/assets/javascripts/right_sidebar.js index 009afe03ea6..a3abc8b8e90 100644 --- a/app/assets/javascripts/right_sidebar.js +++ b/app/assets/javascripts/right_sidebar.js @@ -7,6 +7,18 @@ import createFlash from './flash'; import axios from './lib/utils/axios_utils'; import { sprintf, s__, __ } from './locale'; +const updateSidebarClasses = (layoutPage, rightSidebar) => { + if (window.innerWidth >= 768) { + layoutPage.classList.remove('right-sidebar-expanded', 'right-sidebar-collapsed'); + rightSidebar.classList.remove('right-sidebar-collapsed'); + rightSidebar.classList.add('right-sidebar-expanded'); + } else { + layoutPage.classList.add('right-sidebar-collapsed', 'is-merge-request'); + rightSidebar.classList.add('right-sidebar-collapsed'); + rightSidebar.classList.remove('right-sidebar-expanded'); + } +}; + function Sidebar() { this.toggleTodo = this.toggleTodo.bind(this); this.sidebar = $('aside'); @@ -42,13 +54,22 @@ Sidebar.prototype.addEventListeners = function () { this.sidebar.on('hiddenGlDropdown', this, this.onSidebarDropdownHidden); $document.on('click', '.js-sidebar-toggle', this.sidebarToggleClicked); - return $(document) - .off('click', '.js-issuable-todo') - .on('click', '.js-issuable-todo', this.toggleTodo); + $(document).off('click', '.js-issuable-todo').on('click', '.js-issuable-todo', this.toggleTodo); + + if (window.gon?.features?.movedMrSidebar) { + const layoutPage = document.querySelector('.layout-page'); + const rightSidebar = document.querySelector('.js-right-sidebar'); + + updateSidebarClasses(layoutPage, rightSidebar); + window.addEventListener('resize', () => updateSidebarClasses(layoutPage, rightSidebar)); + } }; Sidebar.prototype.sidebarToggleClicked = function (e, triggered) { const $this = $(this); + + if ($this.hasClass('right-sidebar-merge-requests')) return; + const $collapseIcon = $('.js-sidebar-collapse'); const $expandIcon = $('.js-sidebar-expand'); const $toggleContainer = $('.js-sidebar-toggle-container'); diff --git a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue index 68deb3761a3..6e18cf36690 100644 --- a/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue +++ b/app/assets/javascripts/sidebar/components/assignees/assignee_title.vue @@ -1,6 +1,7 @@