aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/app
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/sonar-web/src/main/js/app
parent580d16d64bc1465a30704adc0be6dd8f1aabd24e (diff)
downloadsonarqube-cb1d3ed779a9057f0235c5331842f2d0d57a89cd.tar.gz
sonarqube-cb1d3ed779a9057f0235c5331842f2d0d57a89cd.zip
SONAR-23896 Improve MQR tour
Diffstat (limited to 'server/sonar-web/src/main/js/app')
-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
2 files changed, 34 insertions, 7 deletions
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 () => {