diff options
author | Ismail Cherri <ismail.cherri@sonarsource.com> | 2024-12-09 16:13:46 +0100 |
---|---|---|
committer | Steve Marion <steve.marion@sonarsource.com> | 2024-12-18 11:13:21 +0100 |
commit | cb1d3ed779a9057f0235c5331842f2d0d57a89cd (patch) | |
tree | 5bc4333343f030c1f8548f4335fe87a84eb4a978 /server | |
parent | 580d16d64bc1465a30704adc0be6dd8f1aabd24e (diff) | |
download | sonarqube-cb1d3ed779a9057f0235c5331842f2d0d57a89cd.tar.gz sonarqube-cb1d3ed779a9057f0235c5331842f2d0d57a89cd.zip |
SONAR-23896 Improve MQR tour
Diffstat (limited to 'server')
6 files changed, 48 insertions, 16 deletions
diff --git a/server/sonar-web/public/images/mode-tour/step4_se.png b/server/sonar-web/public/images/mode-tour/step4_se.png Binary files differnew file mode 100644 index 00000000000..6475bbdcaf3 --- /dev/null +++ b/server/sonar-web/public/images/mode-tour/step4_se.png diff --git a/server/sonar-web/src/main/js/app/components/ModeTour.tsx b/server/sonar-web/src/main/js/app/components/ModeTour.tsx index c8aa12cba4f..faed47193d3 100644 --- a/server/sonar-web/src/main/js/app/components/ModeTour.tsx +++ b/server/sonar-web/src/main/js/app/components/ModeTour.tsx @@ -111,6 +111,18 @@ export default function ModeTour() { return () => document.removeEventListener(CustomEvents.RunTourMode, listener); }, []); + useEffect(() => { + const listener = () => { + // dismiss tour if help menu is closed and user has not completed all steps + if (step >= MAX_STEPS) { + dismissTour(); + } + }; + document.addEventListener(CustomEvents.HelpMenuClosed, listener); + + return () => document.removeEventListener(CustomEvents.HelpMenuClosed, listener); + }, [dismissTour, step]); + const isAdmin = currentUser.permissions?.global.includes(Permissions.Admin); const isAdminOrQGAdmin = isAdmin || currentUser.permissions?.global.includes(Permissions.QualityGateAdmin); @@ -151,7 +163,6 @@ export default function ModeTour() { title: intl.formatMessage({ id: 'mode_tour.step5.title' }), content: null, placement: 'left', - hideFooter: true, }, ]; @@ -174,10 +185,12 @@ export default function ModeTour() { <Image alt={intl.formatMessage({ id: `mode_tour.step${step}.img_alt` })} className="sw-w-full sw-mb-4" - src={`/images/mode-tour/step${step}.png`} + src={`/images/mode-tour/step${isStandardMode && step === 4 ? step + '_se' : step}.png`} /> {intl.formatMessage( - { id: `mode_tour.step${step}.description` }, + { + id: `mode_tour.step${step}.description`, + }, { mode: intl.formatMessage({ id: `settings.mode.${isStandardMode ? 'standard' : 'mqr'}.name`, @@ -219,12 +232,19 @@ export default function ModeTour() { steps={steps} run={step > maxModalSteps} continuous - disableOverlay={false} + disableOverlay showProgress={step !== 5} stepIndex={step - maxModalSteps - 1} nextLabel={intl.formatMessage({ id: 'next' })} + closeLabel={intl.formatMessage({ id: 'got_it' })} + backLabel="" stepXofYLabel={(x: number) => - intl.formatMessage({ id: 'guiding.step_x_of_y' }, { 0: x + maxModalSteps, 1: MAX_STEPS }) + x + maxModalSteps <= MAX_STEPS + ? intl.formatMessage( + { id: 'guiding.step_x_of_y' }, + { 0: x + maxModalSteps, 1: MAX_STEPS }, + ) + : '' } /> </> diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx index a1135f4bea4..a5767acc77a 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx @@ -41,6 +41,7 @@ const ui = { close: byRole('button', { name: 'modal.close' }), skip: byRole('button', { name: 'skip' }), letsgo: byRole('button', { name: 'lets_go' }), + gotit: byRole('button', { name: 'got_it' }), help: byRole('button', { name: 'help' }), guidePopup: byRole('alertdialog'), tourTrigger: byRole('menuitem', { name: 'mode_tour.name' }), @@ -92,6 +93,7 @@ it('renders the tour for admin', async () => { expect(ui.guidePopup.query()).not.toHaveTextContent('guiding.step_x_of_y'); expect(ui.next.query()).not.toBeInTheDocument(); expect(ui.skip.get()).toBeInTheDocument(); + expect(ui.gotit.get()).toBeInTheDocument(); await user.click(ui.skip.get()); expect(ui.tourTrigger.query()).not.toBeInTheDocument(); @@ -140,7 +142,8 @@ it('renders the tour for gateadmins', async () => { expect(ui.guidePopup.query()).not.toHaveTextContent('guiding.step_x_of_y'); expect(ui.next.query()).not.toBeInTheDocument(); expect(ui.skip.get()).toBeInTheDocument(); - await user.click(ui.skip.get()); + expect(ui.gotit.get()).toBeInTheDocument(); + await user.click(ui.gotit.get()); expect(ui.tourTrigger.query()).not.toBeInTheDocument(); expect(ui.dialog.query()).not.toBeInTheDocument(); @@ -175,7 +178,11 @@ it('should highlight the replay button on closing the dialog', async () => { expect(ui.tourTrigger.get()).toBeInTheDocument(); expect(await ui.guidePopup.find()).toBeInTheDocument(); expect(ui.skip.get()).toBeInTheDocument(); - await user.click(ui.skip.get()); + expect(ui.gotit.get()).toBeInTheDocument(); + // Closing the help menu dismisses the tour as well + await user.click(ui.help.get()); + + expect(ui.guidePopup.query()).not.toBeInTheDocument(); }); it('should not render the tour for regular users', async () => { diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx index 051426aeef0..c131bb452fe 100644 --- a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx +++ b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx @@ -20,6 +20,7 @@ import { DropdownMenu, IconSlideshow } from '@sonarsource/echoes-react'; import * as React from 'react'; +import { HighlightRing } from '~design-system'; import { useCurrentUser } from '../../app/components/current-user/CurrentUserContext'; import { CustomEvents } from '../../helpers/constants'; import { DocLink } from '../../helpers/doc-links'; @@ -102,13 +103,11 @@ export function EmbedDocsPopup() { <DropdownMenu.GroupLabel>{translate('tours')}</DropdownMenu.GroupLabel> - <DropdownMenu.ItemButton - prefix={<IconSlideshow />} - data-guiding-id="mode-tour-2" - onClick={runModeTour} - > - {translate('mode_tour.name')} - </DropdownMenu.ItemButton> + <HighlightRing data-guiding-id="mode-tour-2"> + <DropdownMenu.ItemButton prefix={<IconSlideshow />} onClick={runModeTour}> + {translate('mode_tour.name')} + </DropdownMenu.ItemButton> + </HighlightRing> </> )} </> diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx index 218a4e200e7..0e8066ddff2 100644 --- a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx +++ b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx @@ -25,7 +25,7 @@ import { DropdownMenuAlign, IconQuestionMark, } from '@sonarsource/echoes-react'; -import { useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import { CustomEvents } from '../../helpers/constants'; import { translate } from '../../helpers/l10n'; import { EmbedDocsPopup } from './EmbedDocsPopup'; @@ -44,6 +44,11 @@ export default function EmbedDocsPopupHelper() { }; }, []); + const handleClose = useCallback(() => { + setOpen(false); + document.dispatchEvent(new CustomEvent(CustomEvents.HelpMenuClosed)); + }, []); + return ( <div className="dropdown"> <DropdownMenu.Root @@ -51,7 +56,7 @@ export default function EmbedDocsPopupHelper() { id="help-menu-dropdown" isOpen={open} onOpen={() => setOpen(true)} - onClose={() => setOpen(false)} + onClose={handleClose} items={<EmbedDocsPopup />} > <ButtonIcon diff --git a/server/sonar-web/src/main/js/helpers/constants.ts b/server/sonar-web/src/main/js/helpers/constants.ts index c3d807a14a3..bf0ce79b695 100644 --- a/server/sonar-web/src/main/js/helpers/constants.ts +++ b/server/sonar-web/src/main/js/helpers/constants.ts @@ -288,5 +288,6 @@ export const ONE_SECOND = 1000; export enum CustomEvents { OpenHelpMenu = 'open-help-menu', CloseHelpMenu = 'close-help-menu', + HelpMenuClosed = 'help-menu-closed', RunTourMode = 'runTour-mode', } |