feat(client): add 3 disclosure cde for rdb (#62178)

Co-authored-by: Ahmad Abdolsaheb <ahmad.abdolsaheb@gmail.com>
This commit is contained in:
Shaun Hamilton
2025-10-07 23:27:57 +02:00
committed by GitHub
parent 940a38127b
commit 677ca70eed
8 changed files with 445 additions and 364 deletions
+25 -4
View File
@@ -5,6 +5,15 @@
"aa-test-in-component": {
"defaultValue": false
},
"rdb-codespaces-instructions": {
"defaultValue": true
},
"rdb-local-instructions": {
"defaultValue": true
},
"rdb-ona-instructions": {
"defaultValue": true
},
"landing-top-skill-focused": {
"defaultValue": false,
"rules": [
@@ -13,8 +22,14 @@
"hashAttribute": "id",
"seed": "landing-top-skill-focused",
"hashVersion": 2,
"variations": [false, true],
"weights": [0.5, 0.5],
"variations": [
false,
true
],
"weights": [
0.5,
0.5
],
"key": "landing-top-skill-focused",
"meta": [
{
@@ -39,8 +54,14 @@
"hashAttribute": "id",
"seed": "replace-20-with-25",
"hashVersion": 2,
"variations": [false, true],
"weights": [0.5, 0.5],
"variations": [
false,
true
],
"weights": [
0.5,
0.5
],
"key": "replace-20-with-25",
"meta": [
{
+24 -2
View File
@@ -533,6 +533,26 @@
"project-preview-title": "Here's a preview of what you will build",
"demo-project-title": "Here's an example of a project that meets the requirements",
"github-required": "<0>Create a GitHub</0> account if you don't have one. You'll need it when you create the virtual Linux server machine. This process may take a few minutes.",
"codespaces": {
"intro": "This course runs in a virtual Linux machine using GitHub Codespaces. Follow these instructions to start the course:",
"step-1": "<0>Create an GitHub account</0> if you don't have one",
"step-2": "Click the start button below",
"step-3": "On that page, click the create button",
"step-4": "Once the virtual Linux machine is finished loading, start the CodeRoad extension by:",
"step-5": "Clicking the \"hamburger\" menu near the top left of the VSCode window,",
"step-6": "Going to the <0>View</0> menu,",
"step-7": "Clicking on the <0>Command Palette</0> option,",
"step-8": "and running the <0>CodeRoad: Start</0> command",
"step-9": "Follow the instructions in CodeRoad to complete the course",
"continue-project": "Clicking the button below will start a new project. If you have previously started the {{title}} course, go to the <0>repository page</0> to re-open a previous workspace.",
"learn-more": "Learn more about <0>Codespace workspaces</0>.",
"logout-warning": "If you log out of freeCodeCamp before you complete the entire {{course}} course, your progress will not be saved to your freeCodeCamp account.",
"sub-step-3": "Navigate to your <0>Codespaces secrets page</0>",
"sub-step-4": "Create a new secret named <0>CODEROAD_WEBHOOK_TOKEN</0>",
"sub-step-5": "In the <0>Value</0> field, paste your token",
"sub-step-6": "In the <0>Repository access</0> field, select the <1>freeCodeCamp/rdb-alpha</1> repository",
"summary": "Codespaces Setup"
},
"ona": {
"intro": "This course runs in a virtual Linux machine using Ona. Follow these instructions to start the course:",
"step-1": "<0>Create an Ona account</0> if you don't have one",
@@ -549,7 +569,8 @@
"logout-warning": "If you log out of freeCodeCamp before you complete the entire {{course}} course, your progress will not be saved to your freeCodeCamp account.",
"sub-step-3": "Navigate to your <0>Ona secrets page</0>",
"sub-step-4": "Create a new secret named <0>CODEROAD_WEBHOOK_TOKEN</0>",
"sub-step-5": "In the <0>Secret</0> field, paste your token"
"sub-step-5": "In the <0>Secret</0> field, paste your token",
"summary": "Ona Setup"
},
"local": {
"intro": "This course runs in a virtual Linux machine on your computer. To run the course, you first need to download each of the following if you don't already have them:",
@@ -571,7 +592,8 @@
"step-7": "Copy the course URL below, paste it in the URL input, and click \"Load\".",
"copy-url": "Copy Course URL",
"step-8": "Click \"Start\" to begin.",
"step-9": "Follow the instructions in CodeRoad to complete the course. Note: You may need to restart the terminal once for terminal settings to take effect and the tests to pass."
"step-9": "Follow the instructions in CodeRoad to complete the course. Note: You may need to restart the terminal once for terminal settings to take effect and the tests to pass.",
"summary": "Local Setup"
},
"step-1": "Step 1: Complete the project",
"step-2": "Step 2: Submit your code",
@@ -0,0 +1,190 @@
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { Spacer, Button, Callout } from '@freecodecamp/ui';
import { CodeAllyButton } from '../../../components/growth-book/codeally-button';
interface CodespacesInstructionsProps {
challengeType: number;
copyUrl: () => void;
copyUserToken: () => void;
generateUserToken: () => Promise<void>;
isSignedIn: boolean;
title: string;
userToken: string | null;
}
export function CodespacesInstructions({
challengeType,
copyUrl,
copyUserToken,
generateUserToken,
isSignedIn,
title,
userToken
}: CodespacesInstructionsProps) {
const { t } = useTranslation();
function openCodespaces() {
const codespacesUrl = `https://codespaces.new/freeCodeCamp/rdb-alpha`;
window.open(codespacesUrl, '_blank');
}
return (
<div className='ca-description'>
<p>{t('learn.codespaces.intro')}</p>
<ol>
<li>
<Trans i18nKey='learn.codespaces.step-1'>
<a
href='https://github.com/signup'
rel='noopener noreferrer'
target='_blank'
>
placeholder
</a>
</Trans>
</li>
{isSignedIn && (
<>
<Spacer size='s' />
<p>{t('learn.local.sub-step-heading')}</p>
<ol>
<li>{t('learn.local.sub-step-1')}</li>
<Spacer size='xxs' />
<Button
disabled={!!userToken}
block={true}
onClick={() => void generateUserToken()}
>
{t('learn.local.generate-token-btn')}
</Button>
<Spacer size='xs' />
<li>{t('learn.local.sub-step-2')}</li>
<Spacer size='xxs' />
<Button
disabled={!userToken}
block={true}
onClick={copyUserToken}
>
{t('learn.local.copy-token-btn')}
</Button>
<Spacer size='xs' />
<li>
<Trans i18nKey='learn.codespaces.sub-step-3'>
<a
href='https://github.com/settings/codespaces/secrets/new'
rel='noopener noreferrer'
target='_blank'
>
Codespaces secrets page
</a>
</Trans>
</li>
<li>
<Trans i18nKey='learn.codespaces.sub-step-4'>
<code>placeholder</code>
</Trans>
</li>
<li>
<Trans i18nKey='learn.codespaces.sub-step-5'>
<code>placeholder</code>
</Trans>
</li>
<li>
<Trans i18nKey='learn.codespaces.sub-step-6'>
<code>placeholder</code>
<code>placeholder</code>
</Trans>
</li>
</ol>
<Spacer size='s' />
</>
)}
<li>{t('learn.codespaces.step-2')}</li>
<li>{t('learn.codespaces.step-3')}</li>
<li>
{t('learn.codespaces.step-4')}
<ul>
<li>{t('learn.codespaces.step-5')}</li>
<li>
<Trans i18nKey='learn.codespaces.step-6'>
<code>placeholder</code>
</Trans>
</li>
<li>
<Trans i18nKey='learn.codespaces.step-7'>
<code>placeholder</code>
</Trans>
</li>
<li>
<Trans i18nKey='learn.codespaces.step-8'>
<code>placeholder</code>
</Trans>
</li>
<li>{t('learn.local.step-6')}</li>
<li>{t('learn.local.step-7')}</li>
<Spacer size='xxs' />
<Button block={true} onClick={copyUrl}>
{t('learn.local.copy-url')}
</Button>
<Spacer size='xs' />
<li>{t('learn.local.step-8')}</li>
</ul>
</li>
<li>{t('learn.codespaces.step-9')}</li>
</ol>
<Spacer size='m' />
<CodespacesContinueAlert title={title} />
{isSignedIn && <CodespacesLogoutAlert course={title} />}
<CodeAllyButton challengeType={challengeType} onClick={openCodespaces} />
</div>
);
}
interface CodespacesContinueAlertProps {
title: string;
}
function CodespacesContinueAlert({ title }: CodespacesContinueAlertProps) {
return (
<Callout variant='info'>
<Trans values={{ title }} i18nKey='learn.codespaces.continue-project'>
<a
href='https://github.com/freeCodeCamp/rdb-alpha'
rel='noopener noreferrer'
target='_blank'
>
placeholder
</a>
</Trans>
<Spacer size='m' />
<Trans i18nKey='learn.codespaces.learn-more'>
<a
href='https://forum.freecodecamp.org/t/relational-database-curriculum-in-codespaces/761449'
rel='noopener noreferrer'
target='_blank'
>
placeholder
</a>
</Trans>
</Callout>
);
}
interface CodespacesLogoutAlertProps {
course: string;
}
function CodespacesLogoutAlert({
course
}: CodespacesLogoutAlertProps): JSX.Element {
const { t } = useTranslation();
return (
<Callout variant='danger'>
{t('learn.codespaces.logout-warning', { course })}
</Callout>
);
}
@@ -1,103 +1,29 @@
import React from 'react';
import { connect } from 'react-redux';
import { Trans, useTranslation } from 'react-i18next';
import { Spacer, Button } from '@freecodecamp/ui';
import { postUserToken } from '../../../utils/ajax';
import { createFlashMessage } from '../../../components/Flash/redux';
import { FlashMessages } from '../../../components/Flash/redux/flash-messages';
import {
isSignedInSelector,
userTokenSelector
} from '../../../redux/selectors';
import { updateUserToken } from '../../../redux/actions';
import { Link } from '../../../components/helpers';
import RdbLocalLogoutAlert from './rdb-local-logout-alert';
const mapStateToProps = (state: unknown) => ({
isSignedIn: isSignedInSelector(state),
userToken: userTokenSelector(state) as string | null
});
const mapDispatchToProps = {
createFlashMessage,
updateUserToken
};
interface RdbLocalInstructionsProps {
course: string;
createFlashMessage: typeof createFlashMessage;
interface LocalInstructionsProps {
copyUrl: () => void;
copyUserToken: () => void;
generateUserToken: () => Promise<void>;
isSignedIn: boolean;
updateUserToken: (arg0: string) => void;
url: string;
title: string;
userToken: string | null;
}
function RdbLocalInstructions({
course,
createFlashMessage,
export function LocalInstructions({
copyUrl,
copyUserToken,
generateUserToken,
isSignedIn,
updateUserToken,
url,
title,
userToken
}: RdbLocalInstructionsProps): JSX.Element {
}: LocalInstructionsProps) {
const { t } = useTranslation();
const coderoadTutorial = `https://raw.githubusercontent.com/${url}/main/tutorial.json`;
const generateUserToken = async () => {
const createUserTokenResponse = await postUserToken();
const { data = { userToken: null } } = createUserTokenResponse;
if (data?.userToken) {
updateUserToken(data.userToken);
createFlashMessage({
type: 'success',
message: FlashMessages.UserTokenGenerated
});
} else {
createFlashMessage({
type: 'danger',
message: FlashMessages.UserTokenGenerateError
});
}
};
const copyUserToken = () => {
navigator.clipboard.writeText(userToken ?? '').then(
() => {
createFlashMessage({
type: 'success',
message: FlashMessages.UserTokenCopied
});
},
() => {
createFlashMessage({
type: 'danger',
message: FlashMessages.UserTokenCopyError
});
}
);
};
const copyUrl = () => {
navigator.clipboard.writeText(coderoadTutorial ?? '').then(
() => {
createFlashMessage({
type: 'success',
message: FlashMessages.CourseUrlCopied
});
},
() => {
createFlashMessage({
type: 'danger',
message: FlashMessages.CourseUrlCopyError
});
}
);
};
return (
<div className='ca-description'>
<p>{t('learn.local.intro')}</p>
@@ -174,7 +100,7 @@ function RdbLocalInstructions({
</Trans>
</li>
<Spacer size='xs' />
<RdbLocalLogoutAlert course={course} />
<RdbLocalLogoutAlert title={title} />
</ol>
<Spacer size='s' />
</>
@@ -203,10 +129,3 @@ function RdbLocalInstructions({
</div>
);
}
RdbLocalInstructions.displayName = 'RdbLocalInstructions';
export default connect(
mapStateToProps,
mapDispatchToProps
)(RdbLocalInstructions);
@@ -1,101 +1,40 @@
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { Spacer, Button } from '@freecodecamp/ui';
import { postUserToken } from '../../../utils/ajax';
import { createFlashMessage } from '../../../components/Flash/redux';
import { FlashMessages } from '../../../components/Flash/redux/flash-messages';
import {
isSignedInSelector,
userTokenSelector
} from '../../../redux/selectors';
import { updateUserToken } from '../../../redux/actions';
import { CodeAllyButton } from '../../../components/growth-book/codeally-button';
import RdbLocalLogoutAlert from './rdb-local-logout-alert';
import RdbOnaContinueAlert from './rdb-ona-continue-alert';
import RdbOnaLogoutAlert from './rdb-ona-logout-alert';
const mapStateToProps = (state: unknown) => ({
isSignedIn: isSignedInSelector(state),
userToken: userTokenSelector(state) as string | null
});
const mapDispatchToProps = {
createFlashMessage,
updateUserToken
};
interface RdbOnaInstructionsProps {
course: string;
createFlashMessage: typeof createFlashMessage;
interface OneInstructionsProps {
challengeType: number;
copyUrl: () => void;
copyUserToken: () => void;
generateUserToken: () => Promise<void>;
isSignedIn: boolean;
updateUserToken: (arg0: string) => void;
url: string;
title: string;
userToken: string | null;
}
function RdbOnaInstructions({
course,
createFlashMessage,
export function OnaInstructions({
challengeType,
copyUrl,
copyUserToken,
generateUserToken,
isSignedIn,
updateUserToken,
url,
title,
userToken
}: RdbOnaInstructionsProps): JSX.Element {
}: OneInstructionsProps) {
const { t } = useTranslation();
const coderoadTutorial = `https://raw.githubusercontent.com/${url}/main/tutorial.json`;
function openOna() {
const repoUrl = `https://github.com/freeCodeCamp/rdb-alpha`;
const onaDomain = `https://app.ona.com/`;
const onaUrl = `${onaDomain}#${repoUrl}`;
const generateUserToken = async () => {
const createUserTokenResponse = await postUserToken();
const { data = { userToken: null } } = createUserTokenResponse;
if (data?.userToken) {
updateUserToken(data.userToken);
createFlashMessage({
type: 'success',
message: FlashMessages.UserTokenGenerated
});
} else {
createFlashMessage({
type: 'danger',
message: FlashMessages.UserTokenGenerateError
});
window.open(onaUrl, '_blank');
}
};
const copyUserToken = () => {
navigator.clipboard.writeText(userToken ?? '').then(
() => {
createFlashMessage({
type: 'success',
message: FlashMessages.UserTokenCopied
});
},
() => {
createFlashMessage({
type: 'danger',
message: FlashMessages.UserTokenCopyError
});
}
);
};
const copyUrl = () => {
navigator.clipboard.writeText(coderoadTutorial ?? '').then(
() => {
createFlashMessage({
type: 'success',
message: FlashMessages.CourseUrlCopied
});
},
() => {
createFlashMessage({
type: 'danger',
message: FlashMessages.CourseUrlCopyError
});
}
);
};
return (
<div className='ca-description'>
@@ -158,8 +97,6 @@ function RdbOnaInstructions({
<code>placeholder</code>
</Trans>
</li>
<Spacer size='xs' />
<RdbLocalLogoutAlert course={course} />
</ol>
<Spacer size='s' />
</>
@@ -185,6 +122,7 @@ function RdbOnaInstructions({
<code>placeholder</code>
</Trans>
</li>
<li>{t('learn.local.step-6')}</li>
<li>{t('learn.local.step-7')}</li>
<Spacer size='xxs' />
<Button block={true} onClick={copyUrl}>
@@ -196,10 +134,10 @@ function RdbOnaInstructions({
</li>
<li>{t('learn.ona.step-9')}</li>
</ol>
<Spacer size='m' />
<RdbOnaContinueAlert course={title} />
{isSignedIn && <RdbOnaLogoutAlert course={title} />}
<CodeAllyButton challengeType={challengeType} onClick={openOna} />
</div>
);
}
RdbOnaInstructions.displayName = 'RdbOnaInstructions';
export default connect(mapStateToProps, mapDispatchToProps)(RdbOnaInstructions);
@@ -3,17 +3,15 @@ import { useTranslation } from 'react-i18next';
import { Callout } from '@freecodecamp/ui';
interface RdbLocalLogoutAlertProps {
course: string;
title: string;
}
function RdbLocalLogoutAlert({
course
}: RdbLocalLogoutAlertProps): JSX.Element {
function RdbLocalLogoutAlert({ title }: RdbLocalLogoutAlertProps): JSX.Element {
const { t } = useTranslation();
return (
<Callout variant='danger'>
{t('learn.local.logout-warning', { course })}
{t('learn.local.logout-warning', { course: title })}
</Callout>
);
}
+128 -135
View File
@@ -1,6 +1,6 @@
// Package Utilities
import { graphql } from 'gatsby';
import React, { useEffect, useRef } from 'react';
import React, { Fragment, useEffect, useRef } from 'react';
import Helmet from 'react-helmet';
import type { TFunction } from 'i18next';
import { withTranslation } from 'react-i18next';
@@ -48,16 +48,13 @@ import { FlashMessages } from '../../../components/Flash/redux/flash-messages';
import { SuperBlocks } from '../../../../../shared-dist/config/curriculum';
import { CodeAllyDown } from '../../../components/growth-book/codeally-down';
import { postUserToken } from '../../../utils/ajax';
import { CodeAllyButton } from '../../../components/growth-book/codeally-button';
import RdbOnaContinueAlert from './rdb-ona-continue-alert';
import RdbOnaInstructions from './rdb-ona-instructions';
import RdbOnaLogoutAlert from './rdb-ona-logout-alert';
import RdbLocalInstructions from './rdb-local-instructions';
import RdbStep1Instructions from './rdb-step-1-instructions';
import RdbStep2Instructions from './rdb-step-2-instructions';
import { LocalInstructions } from './local-instructions';
import { OnaInstructions } from './ona-instructions';
import './codeally.css';
import { CodespacesInstructions } from './codespaces-instructions';
// Redux
const mapStateToProps = createSelector(
@@ -116,17 +113,33 @@ interface ShowCodeAllyProps {
userToken: string | null;
}
function ShowCodeAlly(props: ShowCodeAllyProps) {
function ShowCodeAlly({
completedChallenges,
data,
isChallengeCompleted,
isSignedIn,
partiallyCompletedChallenges,
t,
updateSolutionFormValues,
userToken,
updateUserToken,
createFlashMessage,
challengeMounted,
initTests,
pageContext: { challengeMeta },
updateChallengeMeta,
openCompletionModal
}: ShowCodeAllyProps) {
const container = useRef<HTMLElement>(null);
const {
completedChallenges,
data: {
challengeNode: {
challenge: {
block,
challengeType,
fields: { tests },
description,
helpCategory,
id: challengeId,
instructions,
notes,
@@ -136,13 +149,7 @@ function ShowCodeAlly(props: ShowCodeAllyProps) {
url
}
}
},
isChallengeCompleted,
isSignedIn,
partiallyCompletedChallenges,
t,
updateSolutionFormValues
} = props;
} = data;
const blockNameTitle = `${t(
`intro:${superBlock}.blocks.${block}.title`
@@ -158,22 +165,6 @@ function ShowCodeAlly(props: ShowCodeAllyProps) {
);
useEffect(() => {
const {
challengeMounted,
data: {
challengeNode: {
challenge: {
fields: { tests },
challengeType,
helpCategory,
title
}
}
},
pageContext: { challengeMeta },
initTests,
updateChallengeMeta
} = props;
initTests(tests);
const challengePaths = getChallengePaths({
currentCurriculumPaths: challengeMeta
@@ -191,54 +182,11 @@ function ShowCodeAlly(props: ShowCodeAllyProps) {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
function openOna() {
const repoUrl = `https://github.com/freeCodeCamp/rdb-alpha`;
const onaDomain = `https://app.ona.com/`;
const onaUrl = `${onaDomain}#${repoUrl}`;
window.open(onaUrl, '_blank');
}
const startCourse = async () => {
const { isSignedIn, userToken, updateUserToken } = props;
if (!isSignedIn) {
openOna();
} else if (!userToken) {
const createUserTokenResponse = await postUserToken();
const { data = { userToken: null } } = createUserTokenResponse;
if (data?.userToken) {
updateUserToken(data.userToken);
openOna();
} else {
createFlashMessage({
type: 'danger',
message: FlashMessages.StartProjectErr
});
}
} else {
openOna();
}
};
const handleSubmit = ({
showCompletionModal
}: {
showCompletionModal: boolean;
}) => {
const {
completedChallenges,
createFlashMessage,
data: {
challengeNode: {
challenge: { id: challengeId }
}
},
openCompletionModal,
partiallyCompletedChallenges
} = props;
const isPartiallyCompleted = partiallyCompletedChallenges.some(
challenge => challenge.id === challengeId
);
@@ -257,7 +205,85 @@ function ShowCodeAlly(props: ShowCodeAllyProps) {
}
};
const onaDeprecated = useFeature('gitpod-deprecated').on;
const rdbLocalInstructions = useFeature('rdb-local-instructions');
const rdbCodespacesInstructions = useFeature('rdb-codespaces-instructions');
const rdbOnaInstructions = useFeature('rdb-ona-instructions');
const coderoadTutorial = `https://raw.githubusercontent.com/${url}/main/tutorial.json`;
async function generateUserToken() {
const createUserTokenResponse = await postUserToken();
const { data = { userToken: null } } = createUserTokenResponse;
if (data?.userToken) {
updateUserToken(data.userToken);
createFlashMessage({
type: 'success',
message: FlashMessages.UserTokenGenerated
});
} else {
createFlashMessage({
type: 'danger',
message: FlashMessages.UserTokenGenerateError
});
}
}
function copyUserToken() {
navigator.clipboard.writeText(userToken ?? '').then(
() => {
createFlashMessage({
type: 'success',
message: FlashMessages.UserTokenCopied
});
},
() => {
createFlashMessage({
type: 'danger',
message: FlashMessages.UserTokenCopyError
});
}
);
}
function copyUrl() {
navigator.clipboard.writeText(coderoadTutorial ?? '').then(
() => {
createFlashMessage({
type: 'success',
message: FlashMessages.CourseUrlCopied
});
},
() => {
createFlashMessage({
type: 'danger',
message: FlashMessages.CourseUrlCopyError
});
}
);
}
const setups = [
{
name: t('learn.codespaces.summary'),
component: CodespacesInstructions,
on: rdbCodespacesInstructions.on
},
{
name: t('learn.local.summary'),
component: LocalInstructions,
on: rdbLocalInstructions.on
},
{
name: t('learn.ona.summary'),
component: OnaInstructions,
on: rdbOnaInstructions.on
}
];
const setupsToShow = setups.filter(setup => {
return setup.on;
});
return (
<Hotkeys containerRef={container}>
@@ -279,12 +305,32 @@ function ShowCodeAlly(props: ShowCodeAllyProps) {
<PrismFormatted text={description} />
<Spacer size='m' />
{onaDeprecated ? (
<>
<RdbLocalInstructions course={title} url={url} />
{setupsToShow.map(({ name, component: SetupComponent }, i) => (
<Fragment key={name}>
<details
open={i === 0}
style={{ border: '1px solid #ccc', padding: '16px' }}
>
<summary>{name}</summary>
<Spacer size='s' />
<SetupComponent
{...{
challengeType,
copyUrl,
copyUserToken,
generateUserToken,
isSignedIn,
title,
userToken
}}
/>
</details>
<Spacer size='s' />
</Fragment>
))}
<Spacer size='m' />
{isSignedIn &&
challengeType === challengeTypes.codeAllyCert && (
{isSignedIn && challengeType === challengeTypes.codeAllyCert && (
<>
<div className='ca-description'>
{t('learn.complete-both-steps')}
@@ -310,59 +356,6 @@ function ShowCodeAlly(props: ShowCodeAllyProps) {
/>
</>
)}
</>
) : (
<>
<RdbOnaInstructions course={title} url={url} />
<Spacer size='m' />
{isSignedIn &&
challengeType === challengeTypes.codeAllyCert ? (
<>
<div className='ca-description'>
{t('learn.complete-both-steps')}
</div>
<hr />
<Spacer size='m' />
<RdbStep1Instructions
instructions={instructions}
isCompleted={isPartiallyCompleted || isCompleted}
/>
<Spacer size='m' />
<RdbOnaContinueAlert course={title} />
{isSignedIn && <RdbOnaLogoutAlert course={title} />}
<CodeAllyButton
challengeType={challengeType}
//eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={startCourse}
/>
<hr />
<Spacer size='m' />
<RdbStep2Instructions
isCompleted={isCompleted}
notes={notes}
/>
<Spacer size='m' />
<SolutionForm
challengeType={challengeType}
description={description}
onSubmit={handleSubmit}
updateSolutionForm={updateSolutionFormValues}
/>
</>
) : (
<>
<RdbOnaContinueAlert course={title} />
{isSignedIn && <RdbOnaLogoutAlert course={title} />}
<CodeAllyButton
challengeType={challengeType}
//eslint-disable-next-line @typescript-eslint/no-misused-promises
onClick={startCourse}
/>
</>
)}
<Spacer size='xxs' />
</>
)}
<ProjectToolPanel />
<br />
+1 -1
View File
@@ -28,7 +28,7 @@ test.describe('After creating token', () => {
await page.goto(
'/learn/relational-database/learn-bash-by-building-a-boilerplate/build-a-boilerplate'
);
await page.getByRole('button', { name: 'Start the course' }).click();
await page.getByText('Generate User Token').first().click();
await page.goto('/settings');
// Set `exact` to `true` to only match the panel heading