import { useAppState } from './app-state/withAppStateContext';
import { CurrentUserContext } from './current-user/CurrentUserContext';
+const MAX_STEPS = 4;
+
export default function ModeTour() {
const { currentUser, updateDismissedNotices } = useContext(CurrentUserContext);
const appState = useAppState();
const [step, setStep] = useState(1);
const [runManually, setRunManually] = useState(false);
- const steps: SpotlightTourStep[] = [
- {
- target: '[data-guiding-id="mode-tour-1"]',
- content: intl.formatMessage(
- { id: 'mode_tour.step4.description' },
- {
- mode: intl.formatMessage({
- id: `settings.mode.${isStandardMode ? 'standard' : 'mqr'}.name`,
- }),
- p1: (text) => <p>{text}</p>,
- p: (text) => <p className="sw-mt-2">{text}</p>,
- b: (text) => <b>{text}</b>,
- },
- ),
- title: intl.formatMessage({ id: 'mode_tour.step4.title' }),
- placement: 'bottom',
- },
- {
- target: '[data-guiding-id="mode-tour-2"]',
- title: intl.formatMessage({ id: 'mode_tour.step5.title' }),
- content: null,
- placement: 'left',
- hideFooter: true,
- },
- ];
-
const nextStep = () => {
- if ((step === 3 && !isAdmin) || step === 4) {
+ if (step === MAX_STEPS) {
document.dispatchEvent(new CustomEvent(CustomEvents.OpenHelpMenu));
setTimeout(() => setStep(5));
} else {
return null;
}
- const maxSteps = isAdmin ? 4 : 3;
+ const steps: SpotlightTourStep[] = [
+ ...(isAdmin
+ ? [
+ {
+ target: '[data-guiding-id="mode-tour-1"]',
+ content: intl.formatMessage(
+ { id: 'mode_tour.step4.description' },
+ {
+ mode: intl.formatMessage({
+ id: `settings.mode.${isStandardMode ? 'standard' : 'mqr'}.name`,
+ }),
+ p1: (text) => <p>{text}</p>,
+ p: (text) => <p className="sw-mt-2">{text}</p>,
+ b: (text) => <b>{text}</b>,
+ },
+ ),
+ title: intl.formatMessage({ id: 'mode_tour.step4.title' }),
+ placement: 'bottom' as const,
+ },
+ ]
+ : []),
+ {
+ target: '[data-guiding-id="mode-tour-2"]',
+ title: intl.formatMessage({ id: 'mode_tour.step5.title' }),
+ content: null,
+ placement: 'left',
+ hideFooter: true,
+ },
+ ];
+
+ const maxModalSteps = isAdmin ? MAX_STEPS - 1 : MAX_STEPS;
return (
<>
<Modal
size={ModalSize.Wide}
- isOpen={step <= 3}
+ isOpen={step <= maxModalSteps}
onOpenChange={(isOpen) => isOpen === false && dismissTour()}
title={
- step < 4 &&
+ step <= maxModalSteps &&
intl.formatMessage({ id: `mode_tour.step${step}.title` }, { version: appState.version })
}
content={
<>
- {step < 4 && (
+ {step <= maxModalSteps && (
<>
<Image
alt={intl.formatMessage({ id: `mode_tour.step${step}.img_alt` })}
{intl.formatMessage(
{ id: `mode_tour.step${step}.description` },
{
+ mode: intl.formatMessage({
+ id: `settings.mode.${isStandardMode ? 'standard' : 'mqr'}.name`,
+ }),
p1: (text) => <p>{text}</p>,
p: (text) => <p className="sw-mt-4">{text}</p>,
b: (text) => <b>{text}</b>,
)}
<div className="sw-mt-6">
<b>
- {intl.formatMessage({ id: 'guiding.step_x_of_y' }, { 0: step, 1: maxSteps })}
+ {intl.formatMessage({ id: 'guiding.step_x_of_y' }, { 0: step, 1: MAX_STEPS })}
</b>
</div>
</>
<SpotlightTour
callback={onToggle}
steps={steps}
- run={step > 3}
+ run={step > maxModalSteps}
continuous
+ disableOverlay={step === 5}
showProgress={step !== 5}
- stepIndex={step - 4}
+ stepIndex={step - maxModalSteps - 1}
nextLabel={intl.formatMessage({ id: 'next' })}
stepXofYLabel={(x: number) =>
- intl.formatMessage({ id: 'guiding.step_x_of_y' }, { 0: x + 3, 1: maxSteps })
+ intl.formatMessage({ id: 'guiding.step_x_of_y' }, { 0: x + maxModalSteps, 1: MAX_STEPS })
}
/>
</>
step1Dialog: byRole('dialog', { name: /mode_tour.step1.title/ }),
step2Dialog: byRole('dialog', { name: /mode_tour.step2.title/ }),
step3Dialog: byRole('dialog', { name: /mode_tour.step3.title/ }),
+ step4Dialog: byRole('dialog', { name: /mode_tour.step4.title/ }),
next: byRole('button', { name: 'next' }),
later: byRole('button', { name: 'later' }),
skip: byRole('button', { name: 'skip' }),
expect(ui.later.get()).toBeInTheDocument();
expect(ui.next.query()).not.toBeInTheDocument();
expect(ui.letsgo.get()).toBeInTheDocument();
- expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.3');
+ expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.4');
await user.click(ui.letsgo.get());
expect(ui.step2Dialog.get()).toBeInTheDocument();
expect(ui.later.query()).not.toBeInTheDocument();
expect(ui.next.get()).toBeInTheDocument();
expect(ui.letsgo.query()).not.toBeInTheDocument();
- expect(ui.step2Dialog.get()).toHaveTextContent('guiding.step_x_of_y.2.3');
+ expect(ui.step2Dialog.get()).toHaveTextContent('guiding.step_x_of_y.2.4');
await user.click(ui.next.get());
expect(ui.step3Dialog.get()).toBeInTheDocument();
expect(ui.step2Dialog.query()).not.toBeInTheDocument();
expect(ui.next.get()).toBeInTheDocument();
- expect(ui.step3Dialog.get()).toHaveTextContent('guiding.step_x_of_y.3.3');
+ expect(ui.step3Dialog.get()).toHaveTextContent('guiding.step_x_of_y.3.4');
+ await user.click(ui.next.get());
+
+ expect(ui.step4Dialog.get()).toBeInTheDocument();
+ expect(ui.step3Dialog.query()).not.toBeInTheDocument();
+ expect(ui.next.get()).toBeInTheDocument();
+ expect(ui.step4Dialog.get()).toHaveTextContent('guiding.step_x_of_y.4.4');
await user.click(ui.next.get());
expect(ui.dialog.query()).not.toBeInTheDocument();
await user.click(ui.help.get());
await user.click(ui.tourTrigger.get());
expect(ui.step1Dialog.get()).toBeInTheDocument();
- expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.3');
+ expect(ui.step1Dialog.get()).toHaveTextContent('guiding.step_x_of_y.1.4');
});
it('should not render the tour for regular users', async () => {
mode_tour.step3.img_alt=Visual presentation of the new Software Quality badges: Security, Reliability and Maintainability and their connection to the corresponding Standard Experience badges
mode_tour.step3.description=<p1>The new Multi-Quality Rule Mode aims to more accurately represent an issue's impact on all software qualities. </p1><p>It does this by assigning a separate severity to a rule for each software quality (Security, Reliability, and Maintainability), which replaces the types (Vulnerabilities, Bugs, and Code Smells). You can customize the severity level with appropriate permissions.</p><p>This approach focuses on ensuring the impact on all software qualities is clear, not just the one most severely impacted.</p>
mode_tour.step4.title=Switch modes
-mode_tour.step4.description=<p1>You are currently in <b>{mode}</b>.</p1><p>To change it, go to Administration > Configuration > General Settings > Mode.</p><p>Your instance will start in the mode that most closely resembles the software version you are upgrading from.</p>
+mode_tour.step4.img_alt=Visual presentation of switch between Standard Experience and MQR mode in the Administation settings
+mode_tour.step4.description=<p1>You are currently in <b>{mode}</b>.</p1><p>It can be changed with sufficient permissions by going to Administration > Configuration > General Settings > Mode.</p><p>Your instance will start in the mode that most closely resembles the software version you are upgrading from.</p>
mode_tour.step5.title=You can replay the tour from the help section