mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
feat(ui): view challenge source link (#66305)
Co-authored-by: Mrugesh Mohapatra <1884376+raisedadead@users.noreply.github.com> Co-authored-by: Ahmad Abdolsaheb <ahmad.abdolsaheb@gmail.com>
This commit is contained in:
@@ -2,3 +2,4 @@ export const MAX_MOBILE_WIDTH = 767;
|
||||
export const EX_SMALL_VIEWPORT_HEIGHT = 300;
|
||||
export const TOOL_PANEL_HEIGHT = 37;
|
||||
export const SEARCH_EXPOSED_WIDTH = 980;
|
||||
export const GITHUB_LOCATION = 'https://github.com/freeCodeCamp';
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
"sign-in-with-google": "Sign in with Google",
|
||||
"go-to-dcc-today": "Go to Today's Challenge",
|
||||
"go-to-dcc-archive": "Go to Daily Coding Challenge Archive",
|
||||
"challenge-source": "View Challenge Source",
|
||||
"outline": "Outline"
|
||||
},
|
||||
"daily-coding-challenges": {
|
||||
@@ -1421,7 +1422,8 @@
|
||||
"too-long-three": "Please copy/paste all the editor code showing in the challenge from where you just linked.",
|
||||
"add-code-one": "Replace these two sentences with your copied code.",
|
||||
"add-code-two": "Please leave the ``` line above and the ``` line below,",
|
||||
"add-code-three": "because they allow your code to properly format in the post."
|
||||
"add-code-three": "because they allow your code to properly format in the post.",
|
||||
"git-info": "Github Link: {{gitLink}}"
|
||||
},
|
||||
"user-token": {
|
||||
"title": "User Token",
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import { describe, it, expect, vi, afterEach } from 'vitest';
|
||||
|
||||
describe('generateGitHubLink', () => {
|
||||
afterEach(() => vi.resetModules());
|
||||
it('should return a link to a challenge for an english block', async () => {
|
||||
vi.doMock('../../config/env.json', () => ({
|
||||
default: {
|
||||
curriculumLocale: 'english'
|
||||
}
|
||||
}));
|
||||
const { generateGithubLink } = await import('./create-github-link');
|
||||
const link = generateGithubLink(
|
||||
'5d5a813321b9e3db6c106a46',
|
||||
'learn-basic-javascript-by-building-a-role-playing-game'
|
||||
);
|
||||
|
||||
expect(link).toBe(
|
||||
'https://github.com/freeCodeCamp/freeCodeCamp/blob/main/curriculum/challenges/english/blocks/learn-basic-javascript-by-building-a-role-playing-game/5d5a813321b9e3db6c106a46.md'
|
||||
);
|
||||
});
|
||||
|
||||
it('should return a link for a challenge in the Spanish curriculum', async () => {
|
||||
vi.doMock('../../config/env.json', () => ({
|
||||
default: {
|
||||
curriculumLocale: 'espanol'
|
||||
}
|
||||
}));
|
||||
const { generateGithubLink } = await import('./create-github-link');
|
||||
|
||||
const link = generateGithubLink(
|
||||
'5d5a813321b9e3db6c106a46',
|
||||
'learn-basic-javascript-by-building-a-role-playing-game'
|
||||
);
|
||||
|
||||
expect(link).toBe(
|
||||
'https://github.com/freeCodeCamp/i18n-curriculum/blob/main/curriculum/challenges/espanol/blocks/learn-basic-javascript-by-building-a-role-playing-game/5d5a813321b9e3db6c106a46.md'
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import envData from '../../config/env.json';
|
||||
import { GITHUB_LOCATION } from '../../config/misc';
|
||||
|
||||
const { curriculumLocale } = envData;
|
||||
|
||||
export const generateGithubLink = (challengeId: string, block: string) => {
|
||||
const repository =
|
||||
curriculumLocale === 'english' ? '/freeCodeCamp' : '/i18n-curriculum';
|
||||
const gitURL = new URL(GITHUB_LOCATION);
|
||||
|
||||
gitURL.pathname =
|
||||
gitURL.pathname +
|
||||
[
|
||||
repository,
|
||||
'blob/main/curriculum/challenges',
|
||||
curriculumLocale,
|
||||
'blocks',
|
||||
block,
|
||||
`${challengeId}.md`
|
||||
].join('/');
|
||||
return gitURL.toString();
|
||||
};
|
||||
@@ -203,6 +203,7 @@ function ShowClassic({
|
||||
title,
|
||||
description,
|
||||
instructions,
|
||||
id,
|
||||
hooks,
|
||||
tests,
|
||||
challengeType,
|
||||
@@ -421,6 +422,8 @@ function ShowClassic({
|
||||
description={description}
|
||||
instructions={instructions}
|
||||
superBlock={superBlock}
|
||||
challengeId={id}
|
||||
block={block}
|
||||
/>
|
||||
}
|
||||
challengeTitle={
|
||||
|
||||
@@ -2,17 +2,22 @@ import React, { useEffect } from 'react';
|
||||
import { initializeMathJax, isMathJaxAllowed } from '../../../utils/math-jax';
|
||||
import PrismFormatted from './prism-formatted';
|
||||
import './challenge-description.css';
|
||||
import { generateGithubLink } from '../../../components/create-github-link';
|
||||
|
||||
type Props = {
|
||||
description?: string;
|
||||
instructions?: string;
|
||||
superBlock?: string;
|
||||
challengeId: string;
|
||||
block: string;
|
||||
};
|
||||
|
||||
const ChallengeDescription = ({
|
||||
description,
|
||||
instructions,
|
||||
superBlock
|
||||
superBlock,
|
||||
challengeId,
|
||||
block
|
||||
}: Props) => {
|
||||
useEffect(() => {
|
||||
if (superBlock && isMathJaxAllowed(superBlock)) {
|
||||
@@ -20,10 +25,12 @@ const ChallengeDescription = ({
|
||||
}
|
||||
}, [superBlock]);
|
||||
|
||||
const githubLink = generateGithubLink(challengeId, block);
|
||||
return (
|
||||
<div
|
||||
className={'challenge-instructions mathjax-support'}
|
||||
data-playwright-test-label='challenge-description'
|
||||
data-github-link={githubLink}
|
||||
>
|
||||
{description && <PrismFormatted text={description} />}
|
||||
{instructions && description && <hr />}
|
||||
|
||||
@@ -120,6 +120,7 @@ const ShowGeneric = ({
|
||||
explanation,
|
||||
challengeType,
|
||||
helpCategory,
|
||||
id,
|
||||
instructions,
|
||||
questions,
|
||||
tests,
|
||||
@@ -297,6 +298,8 @@ const ShowGeneric = ({
|
||||
<ChallengeDescription
|
||||
description={description}
|
||||
superBlock={superBlock}
|
||||
block={block}
|
||||
challengeId={id}
|
||||
/>
|
||||
<Spacer size='m' />
|
||||
</Col>
|
||||
@@ -336,6 +339,8 @@ const ShowGeneric = ({
|
||||
<ChallengeDescription
|
||||
instructions={instructions}
|
||||
superBlock={superBlock}
|
||||
block={block}
|
||||
challengeId={id}
|
||||
/>
|
||||
<Spacer size='m' />
|
||||
</>
|
||||
|
||||
@@ -139,6 +139,7 @@ function MsTrophy(props: MsTrophyProps) {
|
||||
description,
|
||||
instructions,
|
||||
superBlock,
|
||||
id,
|
||||
block,
|
||||
translationPending
|
||||
}
|
||||
@@ -175,6 +176,8 @@ function MsTrophy(props: MsTrophyProps) {
|
||||
superBlock={superBlock}
|
||||
description={description}
|
||||
instructions={instructions}
|
||||
block={block}
|
||||
challengeId={id}
|
||||
/>
|
||||
<LinkMsUser />
|
||||
<hr />
|
||||
|
||||
@@ -144,6 +144,7 @@ const ShowBackEnd = (props: BackEndProps) => {
|
||||
challengeType,
|
||||
forumTopicId,
|
||||
title,
|
||||
id,
|
||||
description,
|
||||
instructions,
|
||||
translationPending,
|
||||
@@ -183,6 +184,8 @@ const ShowBackEnd = (props: BackEndProps) => {
|
||||
superBlock={superBlock}
|
||||
description={description}
|
||||
instructions={instructions}
|
||||
block={block}
|
||||
challengeId={id}
|
||||
/>
|
||||
<Spacer size='m' />
|
||||
<SolutionForm
|
||||
|
||||
@@ -120,6 +120,7 @@ const ShowFrontEndProject = (props: ProjectProps) => {
|
||||
challengeType,
|
||||
forumTopicId,
|
||||
title,
|
||||
id,
|
||||
description,
|
||||
instructions,
|
||||
superBlock,
|
||||
@@ -157,6 +158,8 @@ const ShowFrontEndProject = (props: ProjectProps) => {
|
||||
superBlock={superBlock}
|
||||
description={description}
|
||||
instructions={instructions}
|
||||
block={block}
|
||||
challengeId={id}
|
||||
/>
|
||||
<Spacer size='m' />
|
||||
<SolutionForm
|
||||
|
||||
@@ -98,6 +98,7 @@ const ShowQuiz = ({
|
||||
description,
|
||||
challengeType,
|
||||
helpCategory,
|
||||
id,
|
||||
superBlock,
|
||||
block,
|
||||
tests,
|
||||
@@ -356,6 +357,8 @@ const ShowQuiz = ({
|
||||
<ChallengeDescription
|
||||
description={description}
|
||||
superBlock={superBlock}
|
||||
block={block}
|
||||
challengeId={id}
|
||||
/>
|
||||
<Spacer size='l' />
|
||||
<ObserveKeys>
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
challengeMetaSelector,
|
||||
projectFormValuesSelector
|
||||
} from './selectors';
|
||||
import { generateGithubLink } from '../../../components/create-github-link';
|
||||
|
||||
const { forumLocation } = envData;
|
||||
|
||||
@@ -131,7 +132,8 @@ function createQuestionEpic(action$, state$, { window }) {
|
||||
superBlock,
|
||||
block,
|
||||
helpCategory,
|
||||
challengeType
|
||||
challengeType,
|
||||
id
|
||||
} = challengeMetaSelector(state);
|
||||
|
||||
challengeFiles = insertEditableRegions(challengeFiles);
|
||||
@@ -156,13 +158,18 @@ function createQuestionEpic(action$, state$, { window }) {
|
||||
projectFormValuesSelector(state)
|
||||
);
|
||||
|
||||
const gitLink = generateGithubLink(id, block);
|
||||
const gitInfo = i18next.t('forum-help.git-info', {
|
||||
gitLink
|
||||
});
|
||||
|
||||
const browserInfoHeading = i18next.t('forum-help.browser-info');
|
||||
const userAgentHeading = i18next.t('forum-help.user-agent', {
|
||||
userAgent
|
||||
});
|
||||
const challengeHeading = i18next.t('forum-help.challenge');
|
||||
const blockTitle = i18next.t(`intro:${superBlock}.blocks.${block}.title`);
|
||||
const endingText = `### ${browserInfoHeading}\n\n${userAgentHeading}\n\n### ${challengeHeading}\n${blockTitle} - ${challengeTitle}\n${challengeUrl}`;
|
||||
const endingText = `### ${browserInfoHeading}\n\n${userAgentHeading}\n\n### ${challengeHeading}\n${blockTitle} - ${challengeTitle}\n${challengeUrl}\n${gitInfo}`;
|
||||
|
||||
const camperCodeHeading = nonCodeChallenges.includes(challengeType)
|
||||
? ''
|
||||
|
||||
Reference in New Issue
Block a user