aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorIsmail Cherri <ismail.cherri@sonarsource.com>2024-12-09 16:13:46 +0100
committerSteve Marion <steve.marion@sonarsource.com>2024-12-18 11:13:21 +0100
commitcb1d3ed779a9057f0235c5331842f2d0d57a89cd (patch)
tree5bc4333343f030c1f8548f4335fe87a84eb4a978 /server
parent580d16d64bc1465a30704adc0be6dd8f1aabd24e (diff)
downloadsonarqube-cb1d3ed779a9057f0235c5331842f2d0d57a89cd.tar.gz
sonarqube-cb1d3ed779a9057f0235c5331842f2d0d57a89cd.zip
SONAR-23896 Improve MQR tour
Diffstat (limited to 'server')
-rw-r--r--server/sonar-web/public/images/mode-tour/step4_se.pngbin0 -> 7947 bytes
-rw-r--r--server/sonar-web/src/main/js/app/components/ModeTour.tsx30
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ModeTour-test.tsx11
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx13
-rw-r--r--server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopupHelper.tsx9
-rw-r--r--server/sonar-web/src/main/js/helpers/constants.ts1
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
new file mode 100644
index 00000000000..6475bbdcaf3
--- /dev/null
+++ b/server/sonar-web/public/images/mode-tour/step4_se.png
Binary files differ
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',
}