return (
<Wrapper
+ as={isSimpleOneLine ? 'span' : undefined}
className={classNames(
+ 'sw-code',
{
+ 'sw-py-6': isOneLine && !noCopy,
'code-snippet-highlighted-oneline': isOneLine,
'code-snippet-simple-oneline': isSimpleOneLine,
},
`;
const StyledSingleLineClipboardButton = styled(StyledClipboardButton)`
- ${tw`sw-top-6 sw-bottom-6`}
+ ${tw`sw-top-4 sw-bottom-4`}
`;
interface Props {
children: React.ReactNode;
+ stepNumber?: number;
title: React.ReactNode;
}
-export function TutorialStep(props: Props) {
+export function TutorialStep({ children, title, stepNumber }: Props) {
return (
- <Step>
- <Title>{props.title}</Title>
- <StepDetails>{props.children}</StepDetails>
+ <Step stepNumber={stepNumber}>
+ <Title>{title}</Title>
+ <StepDetails>{children}</StepDetails>
</Step>
);
}
color: ${themeColor('pageTitle')};
`;
-const Step = styled.li`
+const Step = styled.li<{ stepNumber?: number }>`
list-style: none;
- counter-increment: li;
+ counter-increment: li ${(props) => props.stepNumber};
${tw`sw-mt-10`}
it('should show reduced size when single line with no editting', () => {
const { container } = setupWithProps({ isOneLine: true, snippet: 'foobar' });
const copyButton = screen.getByRole('button', { name: 'Copy' });
- expect(copyButton).toHaveStyle('top: 1.5rem');
+ expect(copyButton).toHaveStyle('top: 1rem');
expect(container).toMatchSnapshot();
});
<div>
<div
- class="fs-mask emotion-0 emotion-1"
+ class="sw-code fs-mask emotion-0 emotion-1"
>
<button
aria-describedby="tooltip-1"
right: 1.5rem;
top: 1.5rem;
position: absolute;
- bottom: 1.5rem;
- top: 1.5rem;
+ bottom: 1rem;
+ top: 1rem;
}
.emotion-4:hover,
<div>
<div
- class="code-snippet-highlighted-oneline fs-mask emotion-0 emotion-1"
+ class="sw-code sw-py-6 code-snippet-highlighted-oneline fs-mask emotion-0 emotion-1"
>
<button
aria-describedby="tooltip-2"
await user.click(ui.chooseTutorialLink(TutorialModes.Local).get());
await user.click(screen.getByRole('button', { name: 'onboarding.token.generate' }));
await user.click(screen.getByRole('button', { name: 'continue' }));
- await user.click(screen.getByRole('button', { name: 'onboarding.build.maven' }));
+ await user.click(screen.getByRole('radio', { name: 'onboarding.build.maven' }));
}
async function startJenkinsTutorial(user: UserEvent) {
import { RenderContext, renderApp } from '../../../../helpers/testReactTestingUtils';
import { Permissions } from '../../../../types/permissions';
import { TokenType } from '../../../../types/token';
-import { getCopyToClipboardValue } from '../../test-utils';
+import { getCopyToClipboardValue, getTutorialBuildButtons } from '../../test-utils';
import { OSs } from '../../types';
import AzurePipelinesTutorial, { AzurePipelinesTutorialProps } from '../AzurePipelinesTutorial';
await goToNextStep(user);
//// Analysis step: .NET
- await clickButton(user, 'onboarding.build.dotnet');
+ await user.click(getTutorialBuildButtons().dotnetBuildButton.get());
assertDotNetStepIsCorrectlyRendered();
//// Analysis step: Maven
- await clickButton(user, 'onboarding.build.maven');
+ await user.click(getTutorialBuildButtons().mavenBuildButton.get());
assertMavenStepIsCorrectlyRendered();
//// Analysis step: Gradle
- await clickButton(user, 'onboarding.build.gradle');
+ await user.click(getTutorialBuildButtons().gradleBuildButton.get());
assertGradleStepIsCorrectlyRendered();
//// Analysis step: C Family
- await clickButton(user, 'onboarding.build.cfamily');
+ await user.click(getTutorialBuildButtons().cFamilyBuildButton.get());
// OS's
- await clickButton(user, `onboarding.build.other.os.${OSs.Linux}`);
+ await user.click(getTutorialBuildButtons().linuxButton.get());
assertCFamilyStepIsCorrectlyRendered(OSs.Linux);
- await clickButton(user, `onboarding.build.other.os.${OSs.Windows}`);
+ await user.click(getTutorialBuildButtons().windowsButton.get());
assertCFamilyStepIsCorrectlyRendered(OSs.Windows);
- await clickButton(user, `onboarding.build.other.os.${OSs.MacOS}`);
+ await user.click(getTutorialBuildButtons().macosButton.get());
assertCFamilyStepIsCorrectlyRendered(OSs.MacOS);
//// Analysis step: Other
- await clickButton(user, 'onboarding.build.other');
+ await user.click(getTutorialBuildButtons().otherBuildButton.get());
assertOtherStepIsCorrectlyRendered();
//// Finish tutorial
// No clickable steps.
expect(
screen.queryByRole('button', {
- name: '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
+ name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
})
).not.toBeInTheDocument();
// The first 2 steps become clickable.
expect(
screen.getByRole('button', {
- name: '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
+ name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
})
).toBeInTheDocument();
expect(
screen.getByRole('button', {
- name: '2 onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title',
+ name: 'onboarding.tutorial.with.azure_pipelines.ServiceEndpoint.title',
})
).toBeInTheDocument();
// Navigate back to the first step.
- await clickButton(user, '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title');
+ await clickButton(user, 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title');
// No more clickable steps.
expect(
screen.queryByRole('button', {
- name: '1 onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
+ name: 'onboarding.tutorial.with.azure_pipelines.ExtensionInstallation.title',
})
).not.toBeInTheDocument();
});
await goToNextStep(user);
await goToNextStep(user);
- expect(screen.getByRole('button', { name: 'onboarding.build.dotnet' })).toBeInTheDocument();
- expect(
- screen.queryByRole('button', { name: 'onboarding.build.cfamily' })
- ).not.toBeInTheDocument();
+ expect(getTutorialBuildButtons().dotnetBuildButton.get()).toBeInTheDocument();
+ expect(getTutorialBuildButtons().cFamilyBuildButton.query()).not.toBeInTheDocument();
});
function assertDefaultStepIsCorrectlyRendered() {
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { FlagMessage, Link } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import { Alert } from '../../../components/ui/Alert';
+import { useDocUrl } from '../../../helpers/docs';
import { translate } from '../../../helpers/l10n';
-import DocLink from '../../common/DocLink';
export interface CompilationInfoProps {
className?: string;
}
-export function CompilationInfo({ className = 'spacer-top spacer-bottom' }: CompilationInfoProps) {
+export function CompilationInfo({ className = 'sw-my-2' }: CompilationInfoProps) {
+ const docUrl = useDocUrl();
+
return (
- <Alert className={className} variant="info">
- <p className="spacer-bottom">
- <FormattedMessage
- id="onboarding.tutorial.cfamilly.compilation_database_info"
- defaultMessage={translate('onboarding.tutorial.cfamilly.compilation_database_info')}
- values={{
- link: (
- <DocLink to="/analyzing-source-code/languages/c-family/">
- {translate('onboarding.tutorial.cfamilly.compilation_database_info.link')}
- </DocLink>
- ),
- }}
- />
- </p>
- <p>
- <FormattedMessage
- id="onboarding.tutorial.cfamilly.speed_caching"
- defaultMessage={translate('onboarding.tutorial.cfamilly.speed_caching')}
- values={{
- link: (
- <DocLink to="/analyzing-source-code/languages/c-family/#analysis-cache">
- {translate('onboarding.tutorial.cfamilly.speed_caching.link')}
- </DocLink>
- ),
- }}
- />
- </p>
- </Alert>
+ <FlagMessage className={className} variant="info">
+ <div>
+ <p className="sw-mb-2">
+ <FormattedMessage
+ id="onboarding.tutorial.cfamilly.compilation_database_info"
+ defaultMessage={translate('onboarding.tutorial.cfamilly.compilation_database_info')}
+ values={{
+ link: (
+ <Link to={docUrl('/analyzing-source-code/languages/c-family/')}>
+ {translate('onboarding.tutorial.cfamilly.compilation_database_info.link')}
+ </Link>
+ ),
+ }}
+ />
+ </p>
+ <p>
+ <FormattedMessage
+ id="onboarding.tutorial.cfamilly.speed_caching"
+ defaultMessage={translate('onboarding.tutorial.cfamilly.speed_caching')}
+ values={{
+ link: (
+ <Link to={docUrl('/analyzing-source-code/languages/c-family/#analysis-cache')}>
+ {translate('onboarding.tutorial.cfamilly.speed_caching.link')}
+ </Link>
+ ),
+ }}
+ />
+ </p>
+ </div>
+ </FlagMessage>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ToggleButton } from 'design-system';
import React from 'react';
-import ButtonToggle from '../../controls/ButtonToggle';
import { GradleBuildDSL } from '../types';
interface Props {
return (
<>
<div className={className}>
- <ButtonToggle
+ <ToggleButton
options={buildOptions}
value={build}
- onCheck={(value: GradleBuildDSL) => setBuild(value)}
+ onChange={(value: GradleBuildDSL) => setBuild(value)}
/>
</div>
{children(build)}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { CodeSnippet } from 'design-system';
+import * as React from 'react';
+import { FCProps } from '../../../types/misc';
+
+export function InlineSnippet({ snippet }: Pick<FCProps<typeof CodeSnippet>, 'snippet'>) {
+ return (
+ <CodeSnippet className="sw-code sw-inline-block sw-px-1" noCopy isOneLine snippet={snippet} />
+ );
+}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import classNames from 'classnames';
+import { FlagMessage, Link } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../helpers/docs';
import { translate } from '../../../helpers/l10n';
-import DocLink from '../../common/DocLink';
-import Link from '../../common/Link';
-import { Alert } from '../../ui/Alert';
export interface ProjectTokenScopeInfoProps {
className?: string;
}
export default function ProjectTokenScopeInfo({ className }: ProjectTokenScopeInfoProps) {
+ const docUrl = useDocUrl('/user-guide/user-account/generating-and-using-tokens/');
+
return (
- <Alert variant="info" className={classNames('spacer-top', className)}>
+ <FlagMessage variant="info" className={classNames('sw-mt-2', className)}>
<FormattedMessage
+ tagName="span"
defaultMessage={translate('onboarding.token.warning_project_token_scope')}
id="onboarding.token.warning_project_token_scope"
values={{
{translate('onboarding.token.text.user_account')}
</Link>
),
- doc_link: (
- <DocLink to="/user-guide/user-account/generating-and-using-tokens/">
- {translate('documentation')}
- </DocLink>
- ),
+ doc_link: <Link to={docUrl}>{translate('documentation')}</Link>,
}}
/>
- </Alert>
+ </FlagMessage>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ToggleButton } from 'design-system';
import * as React from 'react';
import { translate } from '../../../helpers/l10n';
-import ButtonToggle from '../../controls/ButtonToggle';
export interface RenderOptionsProps {
checked: string | undefined;
titleLabelKey,
}: RenderOptionsProps) {
return (
- <div className="big-spacer-top">
- {titleLabelKey && <h4 className="spacer-bottom">{translate(titleLabelKey)}</h4>}
+ <div className="sw-mt-4">
+ {titleLabelKey && <label className="sw-block sw-mb-1">{translate(titleLabelKey)}</label>}
- <ButtonToggle
+ <ToggleButton
label={label}
- onCheck={onCheck}
+ onChange={onCheck}
options={options.map((build) => ({
label: translate(optionLabelKey, build),
value: build,
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.onboarding-step {
- position: relative;
- padding-left: 34px;
- margin-bottom: var(--gridSize);
-}
-
-.onboarding-step.no-step-number {
- padding-left: 0;
-}
-
-.onboarding-step:not(.is-open):not(.is-finished) {
- opacity: 0.4;
-}
-
-.onboarding-step .boxed-group-actions {
- height: var(--controlHeight);
- line-height: var(--controlHeight);
-}
-
-.onboarding-step hr {
- margin-left: -72px;
-}
-
-.onboarding-step-number {
- position: absolute;
- top: 15px;
- left: 15px;
- width: 24px;
- height: 24px;
- line-height: 24px;
- border-radius: 24px;
- background-color: #b9b9b9;
- color: #fff;
- font-size: var(--mediumFontSize);
- text-align: center;
-}
-
-.onboarding-step.is-open .onboarding-step-number {
- background-color: var(--darkBlue);
-}
-
-.onboarding-step.is-finished {
- cursor: pointer;
- outline: none;
-}
-
-.onboarding-step .markdown {
- line-height: inherit;
-}
-
-.onboarding-step ol.list-styled,
-.onboarding-step ul.list-styled {
- padding-left: 18px;
-}
-
-.onboarding-step ul.list-styled li {
- margin-top: var(--gridSize);
- margin-bottom: var(--gridSize);
-}
-
-.onboarding-step ol.list-styled > li {
- position: relative;
- counter-increment: li;
- margin-bottom: calc(2 * var(--gridSize));
-}
-
-.onboarding-step ol.list-roman {
- list-style: lower-roman;
-}
-.onboarding-step ol.list-roman > li::marker {
- font-weight: 400;
-}
-
-.onboarding-step ul.list-alpha {
- list-style: lower-alpha;
-}
-.onboarding-step ol.list-styled:not(.list-roman) > li::marker,
-.onboarding-step ul.list-alpha > li::marker {
- font-weight: 500;
-}
-
-.onboarding-step ul.list-alpha > li,
-.onboarding-step ol.list-roman > li {
- margin-bottom: var(--gridSize);
-}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/no-noninteractive-tabindex */
-import classNames from 'classnames';
+import styled from '@emotion/styled';
+import { Card, TutorialStep, TutorialStepList, themeBorder, themeColor } from 'design-system';
import * as React from 'react';
-import './Step.css';
interface Props {
finished?: boolean;
stepTitle: React.ReactNode;
}
+const CLOSED_STEP_OPACITY = 0.4;
+
export default function Step(props: Props) {
const { finished, open, stepNumber, stepTitle } = props;
- const className = classNames('boxed-group', 'onboarding-step', {
- 'is-open': open,
- 'is-finished': finished,
- 'no-step-number': stepNumber === undefined,
- });
const clickable = !open && finished && props.onOpen !== undefined;
};
return (
- <div
- className={className}
+ <StyledCard
+ clickable={Boolean(clickable)}
+ className="sw-mb-2 sw-p-0"
onClick={clickable ? handleClick : undefined}
role={clickable ? 'button' : undefined}
tabIndex={clickable ? 0 : undefined}
>
- {stepNumber !== undefined && <div className="onboarding-step-number">{stepNumber}</div>}
- {!open && props.renderResult && props.renderResult()}
- <div className="boxed-group-header">
- <h2>{stepTitle}</h2>
+ <div
+ style={{ opacity: !open && !finished ? CLOSED_STEP_OPACITY : undefined }}
+ className="sw-flex sw-items-center sw-justify-between sw-px-6"
+ >
+ <TutorialStepList className="sw-flex-1">
+ <TutorialStep title={stepTitle} stepNumber={stepNumber}>
+ {open ? <div>{props.renderForm()}</div> : <div className="boxed-group-inner" />}
+ </TutorialStep>
+ </TutorialStepList>
+ {!open && props.renderResult && props.renderResult()}
</div>
- {open ? <div>{props.renderForm()}</div> : <div className="boxed-group-inner" />}
- </div>
+ </StyledCard>
);
}
+
+const StyledCard = styled(Card)<{ clickable: boolean }>`
+ --focus: ${themeColor('buttonSecondaryBorder')};
+
+ ${({ clickable, theme }) =>
+ clickable &&
+ `
+ cursor: pointer;
+
+
+ &:focus,
+ &:active {
+ outline: ${themeBorder('focus', 'var(--focus)')({ theme })}
+ }
+`};
+`;
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ToggleButton } from 'design-system';
import * as React from 'react';
import { translate } from '../../../helpers/l10n';
-import ButtonToggle from '../../controls/ButtonToggle';
import { withCLanguageFeature } from '../../hoc/withCLanguageFeature';
import GithubCFamilyExampleRepositories from '../components/GithubCFamilyExampleRepositories';
import RenderOptions from '../components/RenderOptions';
return (
<>
<div>
- <h4 className="spacer-bottom">{translate('onboarding.build')}</h4>
- <ButtonToggle
+ <label className="sw-block sw-mb-1">{translate('onboarding.build')}</label>
+ <ToggleButton
label={translate('onboarding.build')}
- onCheck={this.handleBuildToolChange}
+ onChange={this.handleBuildToolChange}
options={buildTools.map((tool) => ({
label: translate('onboarding.build', tool),
value: tool,
{config.buildTool === BuildTools.CFamily && config.os && (
<GithubCFamilyExampleRepositories
- className="big-spacer-top abs-width-600"
+ className="sw-mt-4"
os={config.os}
ci={TutorialModes.Local}
/>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { BasicSeparator, FlagVisual, Link } from 'design-system';
import * as React from 'react';
-import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../helpers/docs';
import { translate } from '../../../helpers/l10n';
import { Component } from '../../../types/types';
-import DocLink from '../../common/DocLink';
export interface DoneNextStepsProps {
component: Component;
export default function DoneNextSteps({ component }: DoneNextStepsProps) {
const isProjectAdmin = component.configuration?.showSettings;
+ const docUrl = useDocUrl();
+
return (
<>
- <hr className="big-spacer-top big-spacer-bottom" />
+ <BasicSeparator className="sw-my-8" />
+
+ <div className="sw-flex sw-justify-center sw-mb-12">
+ <FlagVisual />
+ </div>
<p>
- <strong>{translate('onboarding.analysis.auto_refresh_after_analysis.done')}</strong>{' '}
+ <strong className="sw-font-semibold sw-mr-1">
+ {translate('onboarding.analysis.auto_refresh_after_analysis.done')}
+ </strong>
{translate('onboarding.analysis.auto_refresh_after_analysis.auto_refresh')}
</p>
- <p className="big-spacer-top">
+ <p className="sw-mt-4">
{isProjectAdmin
? translate('onboarding.analysis.auto_refresh_after_analysis.set_up_pr_deco_and_ci.admin')
: translate('onboarding.analysis.auto_refresh_after_analysis.set_up_pr_deco_and_ci')}
</p>
- <p className="big-spacer-top">
- <FormattedMessage
- defaultMessage={translate(
- 'onboarding.analysis.auto_refresh_after_analysis.check_these_links'
- )}
- id="onboarding.analysis.auto_refresh_after_analysis.check_these_links"
- values={{
- link_branches: (
- <DocLink to="/analyzing-source-code/branches/branch-analysis/">
- {translate(
- 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches'
- )}
- </DocLink>
- ),
- link_pr_analysis: (
- <DocLink to="/analyzing-source-code/pull-request-analysis">
- {translate(
- 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis'
- )}
- </DocLink>
- ),
- }}
- />
- </p>
+ <div className="sw-mt-4">
+ <span>
+ {translate('onboarding.analysis.auto_refresh_after_analysis.check_these_links')}
+ </span>
+ <ul className="sw-flex sw-flex-col sw-gap-2 sw-mt-2">
+ <li>
+ <Link to={docUrl('/analyzing-source-code/branches/branch-analysis/')}>
+ {translate(
+ 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches'
+ )}
+ </Link>
+ </li>
+
+ <li>
+ <Link to={docUrl('/analyzing-source-code/pull-request-analysis')}>
+ {translate(
+ 'onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis'
+ )}
+ </Link>
+ </li>
+ </ul>
+ </div>
</>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { LightLabel, PageContentFontWrapper, Title } from 'design-system';
import * as React from 'react';
import { translate } from '../../../helpers/l10n';
import { Component } from '../../../types/types';
import { LoggedInUser } from '../../../types/users';
-import InstanceMessage from '../../common/InstanceMessage';
import ProjectAnalysisStep from './ProjectAnalysisStep';
import TokenStep from './TokenStep';
const { step, token } = this.state;
return (
- <>
- <div className="page-header big-spacer-bottom">
- <h2 className="page-title">{translate('onboarding.project_analysis.header')}</h2>
- <p className="page-description">
- <InstanceMessage message={translate('onboarding.project_analysis.description')} />
- </p>
+ <PageContentFontWrapper className="sw-body-sm">
+ <div className="sw-mb-4">
+ <Title>{translate('onboarding.project_analysis.header')} </Title>
+ <LightLabel>{translate('onboarding.project_analysis.description')}</LightLabel>
</div>
<TokenStep
token={token}
stepNumber={2}
/>
- </>
+ </PageContentFontWrapper>
);
}
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { noop } from 'lodash';
import * as React from 'react';
import { translate } from '../../../helpers/l10n';
import { Component } from '../../../types/types';
renderForm = () => {
const { component, baseUrl, isLocal, token } = this.props;
return (
- <div className="boxed-group-inner">
- <div className="display-flex-column">
- <BuildToolForm onDone={this.handleBuildToolSelect} />
+ <div className="sw-pb-4">
+ <BuildToolForm onDone={this.handleBuildToolSelect} />
- {this.state.config && (
- <div className="big-spacer-top">
- <AnalysisCommand
- component={component}
- baseUrl={baseUrl}
- isLocal={isLocal}
- languageConfig={this.state.config}
- token={token}
- />
- </div>
- )}
- </div>
+ {this.state.config && (
+ <div className="sw-mt-4">
+ <AnalysisCommand
+ component={component}
+ baseUrl={baseUrl}
+ isLocal={isLocal}
+ languageConfig={this.state.config}
+ token={token}
+ />
+ </div>
+ )}
</div>
);
};
- renderResult = () => null;
-
render() {
return (
<Step
finished={false}
- onOpen={() => {
- /* noop */
- }}
+ onOpen={noop}
open={this.props.open}
renderForm={this.renderForm}
- renderResult={this.renderResult}
stepNumber={this.props.stepNumber}
stepTitle={translate('onboarding.analysis.header')}
/>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import {
+ ButtonPrimary,
+ ButtonSecondary,
+ DeferredSpinner,
+ DestructiveIcon,
+ FlagMessage,
+ FlagSuccessIcon,
+ HelperHintIcon,
+ Highlight,
+ InputField,
+ InputSelect,
+ LabelValueSelectOption,
+ Link,
+ Note,
+ RadioButton,
+ TrashIcon,
+} from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { SingleValue } from 'react-select';
import { generateToken, getTokens, revokeToken } from '../../../api/user-tokens';
import { translate } from '../../../helpers/l10n';
import {
import { TokenExpiration, TokenType, UserToken } from '../../../types/token';
import { LoggedInUser } from '../../../types/users';
import DocumentationTooltip from '../../common/DocumentationTooltip';
-import Link from '../../common/Link';
-import Radio from '../../controls/Radio';
-import Select from '../../controls/Select';
-import { Button, DeleteButton, SubmitButton } from '../../controls/buttons';
-import AlertErrorIcon from '../../icons/AlertErrorIcon';
-import AlertSuccessIcon from '../../icons/AlertSuccessIcon';
import ProjectTokenScopeInfo from '../components/ProjectTokenScopeInfo';
import Step from '../components/Step';
import { getUniqueTokenName } from '../utils';
const TOKEN_FORMAT_REGEX = /^[_a-z0-9]+$/;
+enum TokenUse {
+ GENERATE = 'generate',
+ EXISTING = 'use-existing',
+}
+
export default class TokenStep extends React.PureComponent<Props, State> {
mounted = false;
this.state = {
existingToken: '',
loading: false,
- selection: 'generate',
+ selection: TokenUse.GENERATE,
tokenName: props.initialTokenName,
tokenExpiration: TokenExpiration.OneMonth,
tokenExpirationOptions: EXPIRATION_OPTIONS,
}
getToken = () =>
- this.state.selection === 'generate' ? this.state.token : this.state.existingToken;
+ this.state.selection === TokenUse.GENERATE ? this.state.token : this.state.existingToken;
canContinue = () => {
const { existingToken, selection, token } = this.state;
const validExistingToken = TOKEN_FORMAT_REGEX.exec(existingToken) != null;
return (
- (selection === 'generate' && token != null) ||
- (selection === 'use-existing' && existingToken && validExistingToken)
+ (selection === TokenUse.GENERATE && token != null) ||
+ (selection === TokenUse.EXISTING && existingToken && validExistingToken)
);
};
this.setState({ tokenName: event.target.value });
};
- handleTokenExpirationChange = ({ value }: { value: TokenExpiration }) => {
- this.setState({ tokenExpiration: value });
+ handleTokenExpirationChange = (option: SingleValue<LabelValueSelectOption<TokenExpiration>>) => {
+ if (option) {
+ this.setState({ tokenExpiration: option.value });
+ }
};
handleTokenGenerate = async (event: React.FormEvent<HTMLFormElement>) => {
return (
<div>
{tokens !== undefined && tokens.length > 0 ? (
- <Radio
- checked={selection === 'generate'}
+ <RadioButton
+ checked={selection === TokenUse.GENERATE}
onCheck={this.handleModeChange}
- value="generate"
+ value={TokenUse.GENERATE}
>
{translate('onboarding.token.generate', TokenType.Project)}
- </Radio>
+ </RadioButton>
) : (
translate('onboarding.token.generate', TokenType.Project)
)}
- {selection === 'generate' && (
- <div className="big-spacer-top">
- <form className="display-flex-center" onSubmit={this.handleTokenGenerate}>
- <div className="display-flex-column">
- <label className="h3" htmlFor="generate-token-input">
+ {selection === TokenUse.GENERATE && (
+ <div className="sw-mt-4">
+ <form className="sw-flex sw-items-center" onSubmit={this.handleTokenGenerate}>
+ <div className="sw-flex sw-flex-col">
+ <HighlightLabel className="sw-mb-2" htmlFor="generate-token-input">
{translate('onboarding.token.name.label')}
<DocumentationTooltip
- className="spacer-left"
+ className="sw-ml-2"
content={translate('onboarding.token.name.help')}
links={[
{
label: translate('learn_more'),
},
]}
- />
- </label>
- <input
+ >
+ <HelperHintIcon />
+ </DocumentationTooltip>
+ </HighlightLabel>
+ <InputField
id="generate-token-input"
autoFocus
- className="input-super-large spacer-right spacer-top text-middle"
onChange={this.handleTokenNameChange}
required
+ size="large"
type="text"
value={tokenName ?? ''}
/>
</div>
- <div className="display-flex-column spacer-left big-spacer-right">
- <label htmlFor="token-select-expiration" className="h3">
+ <div className="sw-flex sw-flex-col sw-ml-4">
+ <HighlightLabel className="sw-mb-2" htmlFor="token-select-expiration">
{translate('users.tokens.expires_in')}
- </label>
- <div className="display-flex-center">
- <Select
+ </HighlightLabel>
+ <div className="sw-flex sw-items-center">
+ <InputSelect
id="token-select-expiration"
- className="spacer-top abs-width-100 spacer-right"
+ className="sw-w-abs-150 sw-mr-4"
isSearchable={false}
onChange={this.handleTokenExpirationChange}
options={tokenExpirationOptions}
+ size="full"
value={tokenExpirationOptions.find(
(option) => option.value === tokenExpiration
)}
/>
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <SubmitButton className="text-middle spacer-top" disabled={!tokenName}>
- {translate('onboarding.token.generate')}
- </SubmitButton>
- )}
+ <ButtonSecondary
+ type="submit"
+ disabled={!tokenName || loading}
+ icon={<DeferredSpinner className="sw-mr-1" loading={loading} />}
+ >
+ {translate('onboarding.token.generate')}
+ </ButtonSecondary>
</div>
</div>
</form>
const validInput = !existingToken || TOKEN_FORMAT_REGEX.exec(existingToken) != null;
return (
- <div className="big-spacer-top">
- <Radio
- checked={this.state.selection === 'use-existing'}
+ <div className="sw-mt-4">
+ <RadioButton
+ checked={this.state.selection === TokenUse.EXISTING}
onCheck={this.handleModeChange}
- value="use-existing"
+ value={TokenUse.EXISTING}
>
{translate('onboarding.token.use_existing_token')}
- </Radio>
- {this.state.selection === 'use-existing' && (
- <div className="big-spacer-top display-flex-column">
- <label className="h3" htmlFor="existing-token-input">
+ </RadioButton>
+ {this.state.selection === TokenUse.EXISTING && (
+ <div className="sw-flex sw-flex-col sw-mt-4">
+ <HighlightLabel className="sw-mb-2" htmlFor="existing-token-input">
{translate('onboarding.token.use_existing_token.label')}
<DocumentationTooltip
- className="spacer-left"
+ className="sw-ml-2"
content={translate('onboarding.token.use_existing_token.help')}
links={[
{
label: translate('learn_more'),
},
]}
- />
- </label>
- <input
+ >
+ <HelperHintIcon />
+ </DocumentationTooltip>
+ </HighlightLabel>
+ <InputField
id="existing-token-input"
autoFocus
- className="input-super-large spacer-right spacer-top text-middle"
onChange={this.handleExisingTokenChange}
required
+ isInvalid={!validInput}
+ size="large"
type="text"
value={this.state.existingToken}
/>
{!validInput && (
- <span className="text-danger">
- <AlertErrorIcon className="little-spacer-right text-text-top" />
+ <FlagMessage className="sw-mt-2 sw-w-fit" variant="error">
{translate('onboarding.token.invalid_format')}
- </span>
+ </FlagMessage>
)}
</div>
)}
const canUseExisting = tokens !== undefined && tokens.length > 0;
return (
- <div className="boxed-group-inner">
+ <div className="sw-p-4">
{token != null ? (
- <form onSubmit={this.handleTokenRevoke}>
- <span className="text-middle">
+ <form className="sw-flex sw-items-center" onSubmit={this.handleTokenRevoke}>
+ <span>
{tokenName}
{': '}
+ <strong className="sw-font-semibold">{token}</strong>
</span>
- <strong className="spacer-right text-middle">{token}</strong>
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <DeleteButton
- className="button-small text-middle"
+
+ <DeferredSpinner className="sw-ml-3 sw-my-2" loading={loading}>
+ <DestructiveIcon
+ className="sw-ml-1"
+ Icon={TrashIcon}
aria-label={translate('onboarding.token.delete')}
onClick={this.handleTokenRevoke}
/>
- )}
+ </DeferredSpinner>
</form>
) : (
<div>
</div>
)}
- <div className="note big-spacer-top width-50">
+ <Note as="div" className="sw-mt-6 sw-w-1/2">
<FormattedMessage
defaultMessage={translate('onboarding.token.text')}
id="onboarding.token.text"
),
}}
/>
- </div>
+ </Note>
{this.canContinue() && (
- <div className="big-spacer-top">
- <Button className="js-continue" onClick={this.handleContinueClick}>
+ <div className="sw-mt-4">
+ <ButtonPrimary onClick={this.handleContinueClick}>
{translate('continue')}
- </Button>
+ </ButtonPrimary>
</div>
)}
</div>
}
return (
- <div className="boxed-group-actions display-flex-center">
- <AlertSuccessIcon className="spacer-right" />
- {selection === 'generate' && tokenName && `${tokenName}: `}
- <strong>{token}</strong>
+ <div className="sw-flex sw-items-center">
+ <FlagSuccessIcon className="sw-mr-2" />
+ <span>
+ {selection === TokenUse.GENERATE && tokenName && `${tokenName}: `}
+ <strong className="sw-ml-1">{token}</strong>
+ </span>
</div>
);
};
);
}
}
+
+// We need to pass 'htmlFor' to the label, but
+// using 'as' doesn't dynamically change the allowed props
+// https://github.com/emotion-js/emotion/issues/2266
+const HighlightLabel = Highlight.withComponent('label');
// Maven
await user.click(ui.mavenBuildButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('maven: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('maven: execute scanner');
// Gradle
await user.click(ui.gradleBuildButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('gradle: sonarqube plugin');
- expect(getCopyToClipboardValue(1)).toMatchSnapshot('gradle: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('gradle: sonarqube plugin');
+ expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot('gradle: execute scanner');
// Dotnet - Core
await user.click(ui.dotnetBuildButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('dotnet core: install scanner globally');
- expect(getCopyToClipboardValue(1)).toMatchSnapshot('dotnet core: execute command 1');
- expect(getCopyToClipboardValue(2)).toMatchSnapshot('dotnet core: execute command 2');
- expect(getCopyToClipboardValue(3)).toMatchSnapshot('dotnet core: execute command 3');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
+ 'dotnet core: install scanner globally'
+ );
+ expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot('dotnet core: execute command 1');
+ expect(getCopyToClipboardValue(2, 'Copy')).toMatchSnapshot('dotnet core: execute command 2');
+ expect(getCopyToClipboardValue(3, 'Copy')).toMatchSnapshot('dotnet core: execute command 3');
// Dotnet - Framework
await user.click(ui.dotnetFrameworkButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('dotnet framework: execute command 1');
- expect(getCopyToClipboardValue(1)).toMatchSnapshot('dotnet framework: execute command 2');
- expect(getCopyToClipboardValue(2)).toMatchSnapshot('dotnet framework: execute command 3');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('dotnet framework: execute command 1');
+ expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot('dotnet framework: execute command 2');
+ expect(getCopyToClipboardValue(2, 'Copy')).toMatchSnapshot('dotnet framework: execute command 3');
// C Family - Linux
await user.click(ui.cFamilyBuildButton.get());
await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('cfamily linux: execute build wrapper');
- expect(getCopyToClipboardValue(1)).toMatchSnapshot('cfamily linux: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
+ 'cfamily linux: execute build wrapper'
+ );
+ expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot('cfamily linux: execute scanner');
// C Family - Windows
await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('cfamily windows: execute build wrapper');
- expect(getCopyToClipboardValue(1)).toMatchSnapshot('cfamily windows: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
+ 'cfamily windows: execute build wrapper'
+ );
+ expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot('cfamily windows: execute scanner');
// C Family - MacOS
await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('cfamily macos: execute build wrapper');
- expect(getCopyToClipboardValue(1)).toMatchSnapshot('cfamily macos: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot(
+ 'cfamily macos: execute build wrapper'
+ );
+ expect(getCopyToClipboardValue(1, 'Copy')).toMatchSnapshot('cfamily macos: execute scanner');
// Other - Linux
await user.click(ui.otherBuildButton.get());
await user.click(ui.linuxButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('other linux: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('other linux: execute scanner');
// Other - Windows
await user.click(ui.windowsButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('other windows: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('other windows: execute scanner');
// Other - MacOS
await user.click(ui.macosButton.get());
- expect(getCopyToClipboardValue()).toMatchSnapshot('other macos: execute scanner');
+ expect(getCopyToClipboardValue(0, 'Copy')).toMatchSnapshot('other macos: execute scanner');
});
function renderOtherTutorial({
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { CodeSnippet, FlagMessage, SubHeading } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
-import CodeSnippet from '../../../common/CodeSnippet';
-import { Alert } from '../../../ui/Alert';
import { DotNetProps } from './DotNet';
import DotNetExecute from './DotNetExecute';
return (
<div>
- <h4 className="huge-spacer-top spacer-bottom">
+ <SubHeading className="sw-mt-8 sw-mb-2">
{translate('onboarding.analysis.dotnetcore.global')}
- </h4>
- <p className="big-spacer-top markdown">
- {translate('onboarding.analysis.dotnetcore.global.text')}
- </p>
- <CodeSnippet snippet="dotnet tool install --global dotnet-sonarscanner" />
- <Alert className="spacer-top" variant="info">
+ </SubHeading>
+ <p className="sw-mt-4">{translate('onboarding.analysis.dotnetcore.global.text')}</p>
+ <CodeSnippet
+ className="sw-px-4"
+ isOneLine
+ snippet="dotnet tool install --global dotnet-sonarscanner"
+ />
+ <FlagMessage className="sw-mt-2" variant="info">
{translate('onboarding.analysis.dotnetcore.global.text.path')}
- </Alert>
+ </FlagMessage>
<DotNetExecute commands={commands} component={component} />
</div>
);
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { CodeSnippet, Link, SubHeading } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../../helpers/docs';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
-import CodeSnippet from '../../../common/CodeSnippet';
-import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
import DoneNextSteps from '../DoneNextSteps';
}
export default function DotNetExecute({ commands, component }: DotNetExecuteProps) {
+ const docUrl = useDocUrl();
+
return (
<>
- <h4 className="huge-spacer-top spacer-bottom">
+ <SubHeading className="sw-mt-8 sw-mb-2">
{translate('onboarding.analysis.sq_scanner.execute')}
- </h4>
+ </SubHeading>
<InstanceMessage message={translate('onboarding.analysis.msbuild.execute.text')}>
- {(transformedMessage) => <p className="spacer-bottom markdown">{transformedMessage}</p>}
+ {(transformedMessage) => <p className="sw-mb-2">{transformedMessage}</p>}
</InstanceMessage>
- {commands.map((command, index) => (
- <CodeSnippet key={index} snippet={command} />
+ {commands.map((command) => (
+ <CodeSnippet
+ className="sw-px-4"
+ key={command}
+ language="bash"
+ isOneLine
+ wrap
+ snippet={command}
+ />
))}
- <p className="big-spacer-top markdown">
+ <p className="sw-mt-4">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.docs')}
id="onboarding.analysis.docs"
values={{
link: (
- <DocLink to="/analyzing-source-code/scanners/sonarscanner-for-dotnet/">
+ <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-dotnet/')}>
{translate('onboarding.analysis.msbuild.docs_link')}
- </DocLink>
+ </Link>
),
}}
/>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { Link, SubHeading } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../../helpers/docs';
import { translate } from '../../../../helpers/l10n';
-import DocLink from '../../../common/DocLink';
+import { InlineSnippet } from '../../components/InlineSnippet';
import { DotNetProps } from './DotNet';
import DotNetExecute from './DotNetExecute';
export default function DotNetFramework(props: DotNetProps) {
const { baseUrl, component, token } = props;
+ const docUrl = useDocUrl();
+
const commands = [
`SonarScanner.MSBuild.exe begin /k:"${component.key}" /d:sonar.host.url="${baseUrl}" /d:sonar.token="${token}"`,
'MsBuild.exe /t:Rebuild',
return (
<div>
<div>
- <h4 className="spacer-bottom huge-spacer-top">
+ <SubHeading className=" sw-mb-2 sw-mt-8">
{translate('onboarding.analysis.msbuild.header')}
- </h4>
- <p className="markdown">
+ </SubHeading>
+ <p>
<FormattedMessage
defaultMessage={translate('onboarding.analysis.msbuild.text')}
id="onboarding.analysis.msbuild.text"
values={{
- code: <code>%PATH%</code>,
+ code: <InlineSnippet snippet="%PATH%" />,
link: (
- <DocLink to="/analyzing-source-code/scanners/sonarscanner-for-dotnet/">
+ <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-dotnet/')}>
{translate('onboarding.analysis.msbuild.docs_link')}
- </DocLink>
+ </Link>
),
}}
/>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { CodeSnippet, DownloadButton, SubHeading } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { translate } from '../../../../helpers/l10n';
import { getBaseUrl } from '../../../../helpers/system';
-import CodeSnippet from '../../../common/CodeSnippet';
+import { InlineSnippet } from '../../components/InlineSnippet';
import { OSs } from '../../types';
export interface DownloadBuildWrapperProps {
export default function DownloadBuildWrapper(props: DownloadBuildWrapperProps) {
const { os, isLocal, baseUrl } = props;
return (
- <div className="spacer-bottom">
- <h4 className="spacer-bottom">{translate('onboarding.analysis.build_wrapper.header', os)}</h4>
+ <div className="sw-mb-4">
+ <SubHeading className="sw-mb-2">
+ {translate('onboarding.analysis.build_wrapper.header', os)}
+ </SubHeading>
{isLocal ? (
<>
- <p className="spacer-bottom markdown">
+ <p className="sw-mb-2">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.build_wrapper.text')}
id="onboarding.analysis.build_wrapper.text"
values={{
- env_var: <code>{os === 'win' ? '%PATH%' : 'PATH'}</code>,
+ env_var: <InlineSnippet snippet={os === 'win' ? '%PATH%' : 'PATH'} />,
}}
/>
</p>
- <p>
- <a
- className="button"
+ <p className="sw-mb-2">
+ <DownloadButton
download={`${FILENAMES[os]}.zip`}
href={`${getBaseUrl()}/static/cpp/${FILENAMES[os]}.zip`}
rel="noopener noreferrer"
target="_blank"
>
{translate('download_verb')}
- </a>
+ </DownloadButton>
</p>
</>
) : (
- <CodeSnippet snippet={getRemoteDownloadSnippet(os, baseUrl)} />
+ <CodeSnippet
+ className="sw-p-4"
+ language={os === OSs.Windows ? 'powershell' : 'bash'}
+ snippet={getRemoteDownloadSnippet(os, baseUrl)}
+ />
)}
</div>
);
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import {
+ ClipboardIconButton,
+ CodeSnippet,
+ Link,
+ NumberedList,
+ NumberedListItem,
+ SubHeading,
+} from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../../helpers/docs';
import { translate } from '../../../../helpers/l10n';
-import CodeSnippet from '../../../common/CodeSnippet';
-import DocLink from '../../../common/DocLink';
-import { ClipboardButton } from '../../../controls/clipboard';
+import { InlineSnippet } from '../../components/InlineSnippet';
import { OSs } from '../../types';
export interface DownloadScannerProps {
export default function DownloadScanner(props: DownloadScannerProps) {
const { os, isLocal, token } = props;
+ const docUrl = useDocUrl();
+
return (
- <div>
- <h4 className="spacer-bottom">{translate('onboarding.analysis.sq_scanner.header', os)}</h4>
+ <div className="sw-mb-4">
+ <SubHeading className="sw-mb-2">
+ {translate('onboarding.analysis.sq_scanner.header', os)}
+ </SubHeading>
{isLocal ? (
- <p className="spacer-bottom markdown">
+ <p className="sw-mb-2">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.sq_scanner.text')}
id="onboarding.analysis.sq_scanner.text"
values={{
- dir: <code>bin</code>,
- env_var: <code>{os === OSs.Windows ? '%PATH%' : 'PATH'}</code>,
+ dir: <InlineSnippet snippet="bin" />,
+ env_var: <InlineSnippet snippet={os === OSs.Windows ? '%PATH%' : 'PATH'} />,
link: (
- <DocLink to="/analyzing-source-code/scanners/sonarscanner/">
+ <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner/')}>
{translate('onboarding.analysis.sq_scanner.docs_link')}
- </DocLink>
+ </Link>
),
}}
/>
</p>
) : (
<>
- <CodeSnippet snippet={getRemoteDownloadSnippet(os)} />
- <h4 className="spacer-bottom big-spacer-top">
+ <CodeSnippet
+ className="sw-p-4"
+ wrap
+ language={os === OSs.Windows ? 'powershell' : 'bash'}
+ snippet={getRemoteDownloadSnippet(os)}
+ render={`<code>${getRemoteDownloadSnippet(os)}</code>`}
+ />
+ <SubHeading className="sw-mb-2 sw-mt-4">
{translate('onboarding.analysis.sq_scanner.sonar_token_env.header')}
- </h4>
- <ul className="list-styled">
- <li className="markdown">
- {translate('onboarding.analysis.sq_scanner.sonar_token_env.var_name')}:{' '}
- <code>SONAR_TOKEN</code>
- <ClipboardButton className="spacer-left" copyValue="SONAR_TOKEN" />
- </li>
- <li className="markdown">
- {translate('onboarding.analysis.sq_scanner.sonar_token_env.var_value')}:{' '}
- <code>{token}</code>
- <ClipboardButton className="spacer-left" copyValue={token} />
- </li>
- </ul>
+ </SubHeading>
+ <NumberedList>
+ <NumberedListItem className="sw-flex sw-items-center">
+ <span className="sw-mr-1">
+ {translate('onboarding.analysis.sq_scanner.sonar_token_env.var_name')}:
+ </span>
+ <InlineSnippet snippet="SONAR_TOKEN" />
+ <ClipboardIconButton className="sw-ml-2" copyValue="SONAR_TOKEN" />
+ </NumberedListItem>
+ <NumberedListItem className="sw-flex sw-items-center">
+ <span className="sw-mr-1">
+ {translate('onboarding.analysis.sq_scanner.sonar_token_env.var_value')}:
+ </span>
+ <InlineSnippet snippet={token} />
+ <ClipboardIconButton className="sw-ml-2" copyValue={token} />
+ </NumberedListItem>
+ </NumberedList>
</>
)}
</div>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { CodeSnippet, Link, SubHeading } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../../helpers/docs';
import { translate } from '../../../../helpers/l10n';
-import CodeSnippet from '../../../common/CodeSnippet';
-import DocLink from '../../../common/DocLink';
import { OSs } from '../../types';
export interface ExecBuildWrapperProps {
export default function ExecBuildWrapper(props: ExecBuildWrapperProps) {
const { os } = props;
+ const docUrl = useDocUrl();
+
return (
<>
- <h4 className="huge-spacer-top spacer-bottom">
+ <SubHeading className="sw-mt-8 sw-mb-2">
{translate('onboarding.analysis.build_wrapper.execute')}
- </h4>
- <p className="spacer-bottom markdown">
- {translate('onboarding.analysis.build_wrapper.execute_text')}
- </p>
+ </SubHeading>
+ <p className="sw-mb-2">{translate('onboarding.analysis.build_wrapper.execute_text')}</p>
<CodeSnippet
+ className="sw-px-4"
+ isOneLine
snippet={`${executables[os]} --out-dir bw-output ${translate(
'onboarding.analysis.build_wrapper.execute_build_command'
)}`}
/>
- <p className="big-spacer-top markdown">
+ <p className="sw-mt-4">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.build_wrapper.docs')}
id="onboarding.analysis.build_wrapper.docs"
values={{
link: (
- <DocLink to="/analyzing-source-code/languages/c-family/">
+ <Link to={docUrl('/analyzing-source-code/languages/c-family/')}>
{translate('onboarding.analysis.build_wrapper.docs_link')}
- </DocLink>
+ </Link>
),
}}
/>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { CodeSnippet, Link, SubHeading } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../../helpers/docs';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
-import CodeSnippet from '../../../common/CodeSnippet';
-import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
import { OSs } from '../../types';
import { quote } from '../../utils';
export default function ExecScanner(props: ExecScannerProps) {
const { baseUrl, os, isLocal, component, token, cfamily } = props;
+ const docUrl = useDocUrl();
+
const q = quote(os);
const command = [
os === OSs.Windows ? 'sonar-scanner.bat' : 'sonar-scanner',
return (
<div>
- <h4 className="big-spacer-top spacer-bottom">
+ <SubHeading className="sw-mt-4 sw-mb-2">
{translate('onboarding.analysis.sq_scanner.execute')}
- </h4>
+ </SubHeading>
<InstanceMessage message={translate('onboarding.analysis.sq_scanner.execute.text')}>
- {(transformedMessage) => <p className="spacer-bottom markdown">{transformedMessage}</p>}
+ {(transformedMessage) => <p className="sw-mb-2">{transformedMessage}</p>}
</InstanceMessage>
- <CodeSnippet isOneLine={os === OSs.Windows} snippet={command} />
- <p className="big-spacer-top markdown">
+ <CodeSnippet className="sw-p-4" isOneLine={os === OSs.Windows} snippet={command} />
+ <p className="sw-mt-4">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.sq_scanner.docs')}
id="onboarding.analysis.sq_scanner.docs"
values={{
link: (
- <DocLink to="/analyzing-source-code/scanners/sonarscanner/">
+ <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner/')}>
{translate('onboarding.analysis.sq_scanner.docs_link')}
- </DocLink>
+ </Link>
),
}}
/>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { CodeSnippet, Link, Note, SubHeading } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { GRADLE_SCANNER_VERSION } from '../../../../helpers/constants';
+import { useDocUrl } from '../../../../helpers/docs';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
-import CodeSnippet from '../../../common/CodeSnippet';
-import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
import GradleBuildSelection from '../../components/GradleBuildSelection';
+import { InlineSnippet } from '../../components/InlineSnippet';
import { GradleBuildDSL } from '../../types';
import DoneNextSteps from '../DoneNextSteps';
}
const config = {
- [GradleBuildDSL.Groovy]: `plugins {
+ [GradleBuildDSL.Groovy]: {
+ lang: 'groovy',
+ snippet: `plugins {
id "org.sonarqube" version "${GRADLE_SCANNER_VERSION}"
}`,
- [GradleBuildDSL.Kotlin]: `plugins {
+ },
+ [GradleBuildDSL.Kotlin]: {
+ lang: 'kts',
+ snippet: `plugins {
id("org.sonarqube") version "${GRADLE_SCANNER_VERSION}"
}`,
+ },
};
export default function JavaGradle(props: JavaGradleProps) {
const { baseUrl, component, token } = props;
+ const docUrl = useDocUrl();
+
const command = [
'./gradlew sonar',
`-Dsonar.projectKey=${component.key}`,
return (
<div>
- <h4 className="spacer-bottom">{translate('onboarding.analysis.java.gradle.header')}</h4>
+ <SubHeading className="sw-mb-2">
+ {translate('onboarding.analysis.java.gradle.header')}
+ </SubHeading>
<InstanceMessage message={translate('onboarding.analysis.java.gradle.text.1')}>
{(transformedMessage) => (
- <p className="spacer-bottom markdown">
+ <p className="sw-mb-2">
<FormattedMessage
defaultMessage={transformedMessage}
id="onboarding.analysis.java.gradle.text.1"
values={{
- plugin_code: <code>org.sonarqube</code>,
- groovy: <code>{GradleBuildDSL.Groovy}</code>,
- kotlin: <code>{GradleBuildDSL.Kotlin}</code>,
+ plugin_code: <InlineSnippet snippet="org.sonarqube" />,
+ groovy: <InlineSnippet snippet={GradleBuildDSL.Groovy} />,
+ kotlin: <InlineSnippet snippet={GradleBuildDSL.Kotlin} />,
}}
/>
</p>
)}
</InstanceMessage>
- <GradleBuildSelection className="big-spacer-top big-spacer-bottom">
- {(build) => <CodeSnippet snippet={config[build]} />}
+ <GradleBuildSelection className="sw-mt-4 sw-mb-4">
+ {(build) => (
+ <CodeSnippet
+ language={config[build].lang}
+ className="sw-p-4"
+ snippet={config[build].snippet}
+ />
+ )}
</GradleBuildSelection>
- <p className="big-spacer-bottom markdown">
- <em className="small text-muted">
+ <p className="sw-mb-4">
+ <Note as="em">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.java.gradle.latest_version')}
id="onboarding.analysis.java.gradle.latest_version"
values={{
link: (
- <DocLink to="/analyzing-source-code/scanners/sonarscanner-for-gradle/">
+ <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-gradle/')}>
{translate('here')}
- </DocLink>
+ </Link>
),
}}
/>
- </em>
- </p>
- <p className="spacer-top spacer-bottom markdown">
- {translate('onboarding.analysis.java.gradle.text.2')}
+ </Note>
</p>
- <CodeSnippet snippet={command} />
- <p className="big-spacer-top markdown">
+ <p className="sw-mt-2 sw-mb-2">{translate('onboarding.analysis.java.gradle.text.2')}</p>
+ <CodeSnippet className="sw-p-4" snippet={command} />
+ <p className="sw-mt-4">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.docs')}
id="onboarding.analysis.docs"
values={{
link: (
- <DocLink to="/analyzing-source-code/scanners/sonarscanner-for-gradle/">
+ <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-gradle/')}>
{translate('onboarding.analysis.java.gradle.docs_link')}
- </DocLink>
+ </Link>
),
}}
/>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { CodeSnippet, Link, SubHeading } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
+import { useDocUrl } from '../../../../helpers/docs';
import { translate } from '../../../../helpers/l10n';
import { Component } from '../../../../types/types';
-import CodeSnippet from '../../../common/CodeSnippet';
-import DocLink from '../../../common/DocLink';
import InstanceMessage from '../../../common/InstanceMessage';
import DoneNextSteps from '../DoneNextSteps';
`-Dsonar.token=${token}`,
];
+ const docUrl = useDocUrl();
+
return (
<div>
- <h4 className="spacer-bottom">{translate('onboarding.analysis.java.maven.header')}</h4>
- <p className="spacer-bottom markdown">
+ <SubHeading className="sw-mb-2">
+ {translate('onboarding.analysis.java.maven.header')}
+ </SubHeading>
+ <p className="sw-mb-2">
<InstanceMessage message={translate('onboarding.analysis.java.maven.text')} />
</p>
- <CodeSnippet snippet={command} />
- <p className="big-spacer-top markdown">
+ <CodeSnippet className="sw-p-4" snippet={command} />
+ <p className="sw-mt-4">
<FormattedMessage
defaultMessage={translate('onboarding.analysis.docs')}
id="onboarding.analysis.docs"
values={{
link: (
- <DocLink to="/analyzing-source-code/scanners/sonarscanner-for-maven/">
+ <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-maven/')}>
{translate('onboarding.analysis.java.maven.docs_link')}
- </DocLink>
+ </Link>
),
}}
/>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { screen } from '@testing-library/react';
-import { byRole, byText } from '../../helpers/testSelector';
+import { byLabelText, byRole, byText } from '../../helpers/testSelector';
import { BuildTools, GradleBuildDSL, OSs, TutorialModes } from './types';
const CI_TRANSLATE_MAP: Partial<Record<TutorialModes, string>> = {
export function getTutorialBuildButtons() {
return {
- describeBuildTitle: byRole('heading', { name: 'onboarding.build' }),
- mavenBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.Maven}` }),
- gradleBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.Gradle}` }),
- gradleDSLButton: (name: GradleBuildDSL) => byRole('button', { name }),
- dotnetBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.DotNet}` }),
- cFamilyBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.CFamily}` }),
- otherBuildButton: byRole('button', { name: `onboarding.build.${BuildTools.Other}` }),
- windowsDotnetCoreButton: byRole('button', {
+ describeBuildTitle: byLabelText('onboarding.build'),
+ mavenBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Maven}` }),
+ gradleBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Gradle}` }),
+ gradleDSLButton: (name: GradleBuildDSL) => byRole('radio', { name }),
+ dotnetBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.DotNet}` }),
+ cFamilyBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.CFamily}` }),
+ otherBuildButton: byRole('radio', { name: `onboarding.build.${BuildTools.Other}` }),
+ windowsDotnetCoreButton: byRole('radio', {
name: `onboarding.build.${BuildTools.DotNet}.win_core`,
}),
- windowsDotnetFrameworkButton: byRole('button', {
+ windowsDotnetFrameworkButton: byRole('radio', {
name: `onboarding.build.${BuildTools.DotNet}.win_msbuild`,
}),
- linuxDotnetCoreButton: byRole('button', {
+ linuxDotnetCoreButton: byRole('radio', {
name: `onboarding.build.${BuildTools.DotNet}.linux_core`,
}),
- dotnetCoreButton: byRole('button', {
+ dotnetCoreButton: byRole('radio', {
name: `onboarding.build.${BuildTools.DotNet}.variant.dotnet_core`,
}),
- dotnetFrameworkButton: byRole('button', {
+ dotnetFrameworkButton: byRole('radio', {
name: `onboarding.build.${BuildTools.DotNet}.variant.dotnet_framework`,
}),
- linuxButton: byRole('button', { name: `onboarding.build.other.os.${OSs.Linux}` }),
- windowsButton: byRole('button', { name: `onboarding.build.other.os.${OSs.Windows}` }),
- macosButton: byRole('button', { name: `onboarding.build.other.os.${OSs.MacOS}` }),
+ linuxButton: byRole('radio', { name: `onboarding.build.other.os.${OSs.Linux}` }),
+ windowsButton: byRole('radio', { name: `onboarding.build.other.os.${OSs.Windows}` }),
+ macosButton: byRole('radio', { name: `onboarding.build.other.os.${OSs.MacOS}` }),
};
}
: `${url}/${path}`;
}
-export function useDocUrl(to: string) {
+export function useDocUrl(to: string): string;
+export function useDocUrl(): (to: string) => string;
+export function useDocUrl(to?: string) {
const { version, documentationUrl } = React.useContext(AppStateContext);
- return getUrlForDoc(documentationUrl, version, to);
+ if (to) {
+ return getUrlForDoc(documentationUrl, version, to);
+ }
+
+ return (to: string) => getUrlForDoc(documentationUrl, version, to);
}
onboarding.alm.gitlab=GitLab
onboarding.project_analysis.header=Analyze your project
-onboarding.project_analysis.description=We initialized your project on {instance}, now it's up to you to launch analyses!
+onboarding.project_analysis.description=We initialized your project on SonarQube, now it's up to you to launch analyses!
onboarding.project_analysis.guide_to_integrate_pipelines=follow the guide to integrating with Pipelines
onboarding.create_project.setup_manually=Create a project
onboarding.analysis.auto_refresh_after_analysis.auto_refresh=If your analysis is successful, this page will automatically refresh in a few moments.
onboarding.analysis.auto_refresh_after_analysis.set_up_pr_deco_and_ci.admin=You can set up Pull Request Decoration under the project settings. To set up analysis with your favorite CI tool, see the tutorials.
onboarding.analysis.auto_refresh_after_analysis.set_up_pr_deco_and_ci=You can request from a project administrator to set up Pull Request Decoration. To set up analysis with your favorite CI tool, see the tutorials.
-onboarding.analysis.auto_refresh_after_analysis.check_these_links=Check these useful links while you wait: {link_branches}, {link_pr_analysis}.
+onboarding.analysis.auto_refresh_after_analysis.check_these_links=Check these useful links while you wait:
onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis=Pull Request Analysis
onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches=Branch Analysis