feat: transfer The Odin Project to its own superblock (#49202)

* feat: the odin-project superblock

* feat: break everything

* fix: correct meta names

* fix: meta again

* fix: tests

* fix: help category and external curriculum test

* fix: file names again

* fix: help category

* fix: remove console log

---------

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
pull/49295/head^2
Sem Bauke 2023-02-08 15:21:03 +01:00 committed by GitHub
parent 919c1d8c20
commit 928dcbe08c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 160 additions and 53 deletions

View File

@ -778,14 +778,6 @@
"<a href='https://rosettacode.org/wiki/Rosetta_Code' target='_blank' rel='noopener noreferrer nofollow'>Attribute: Rosetta Code</a>"
]
},
"the-odin-project": {
"title": "The Odin Project",
"intro": ["A description is to be determined"]
},
"the-odin-project-projects": {
"title": "The Odin Project Projects",
"intro": ["A description is to be determined"]
},
"project-euler": {
"title": "Project Euler",
"intro": [
@ -795,6 +787,24 @@
}
}
},
"the-odin-project": {
"title": "The Odin Project",
"intro": [
"The Odin Project is one of those \"What I wish I had when I was learning\" resources. ",
"Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway.",
"This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education."
],
"blocks": {
"top-learn-html-foundations": {
"title": "Learn HTML Foundations",
"intro": ["A description is to be determined"]
},
"top-build-a-recipe-project": {
"title": "Learn HTML Foundations by Building a Recipe Page",
"intro": ["A description is to be determined"]
}
}
},
"misc-text": {
"certification": "{{cert}} Certification",
"browse-other": "Browse our other free certifications\n(we recommend doing these in order)",

View File

@ -12,6 +12,7 @@ import Clipboard from './clipboard';
import PythonIcon from './python-icon';
import ResponsiveDesign from './responsive-design';
import Shield from './shield';
import VikingHelmet from './viking-helmet';
const iconMap = {
[SuperBlocks.RespWebDesignNew]: ResponsiveDesign,
@ -27,7 +28,8 @@ const iconMap = {
[SuperBlocks.DataAnalysisPy]: Analytics,
[SuperBlocks.InfoSec]: Shield,
[SuperBlocks.MachineLearningPy]: TensorflowIcon,
[SuperBlocks.CodingInterviewPrep]: Algorithm
[SuperBlocks.CodingInterviewPrep]: Algorithm,
[SuperBlocks.TheOdinProject]: VikingHelmet
};
const generateIconComponent = (

View File

@ -0,0 +1,17 @@
import React from 'react';
function VikingHelmet(
props: JSX.IntrinsicAttributes & React.SVGProps<SVGSVGElement>
): JSX.Element {
return (
<>
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512' {...props}>
<path d='M52.441 53.88c-35.103 34.696-41.31 73.89-33.228 117.837 6.29 34.202 22.079 70.807 40.892 107.767 17.738-27.114 41.117-56.824 68.676-78.517-20.7-17.164-38.261-35.891-51.367-56.447-17.29-27.12-26.504-57.61-24.973-90.64zm407.118 0c1.531 33.03-7.683 63.52-24.973 90.64-13.106 20.556-30.667 39.283-51.367 56.447 27.559 21.693 50.938 51.403 68.676 78.517 18.813-36.96 34.603-73.565 40.892-107.767 8.082-43.947 1.875-83.141-33.228-117.836zM256 179c-8.702 0-17.061 2.757-23 7.316v22.38c6.7-2.648 14.535-4.016 23-4.016s16.3 1.368 23 4.015v-22.379c-5.939-4.559-14.298-7.316-23-7.316zm-41 30.053c-30.485 11.577-60.043 34.66-84.166 62.804C98.718 309.326 76.784 355.501 73.482 391H215V209.053zm82 0V391h141.518c-3.301-35.499-25.236-81.674-57.352-119.143-24.123-28.143-53.681-51.227-84.166-62.804zm-153.502 3.49c-29.097 22.175-55.189 56.212-73.732 85.506a2034.036 2034.036 0 0 0 9.447 17.562c10.162-19.226 23.088-38.126 37.953-55.468 11.983-13.98 25.289-26.965 39.557-38.155a416.25 416.25 0 0 1-13.225-9.445zm225.004 0a416.25 416.25 0 0 1-13.225 9.445c14.268 11.19 27.574 24.175 39.557 38.155 14.865 17.342 27.79 36.242 37.953 55.468 3.179-5.85 6.339-11.705 9.447-17.562-18.543-29.294-44.635-63.33-73.732-85.506zM256 222.68c-7.62 0-14.449 1.66-18.602 3.736-3.262 1.631-4.103 2.973-4.318 3.264.215.29 1.056 1.632 4.318 3.263 4.153 2.077 10.981 3.737 18.602 3.737 7.62 0 14.449-1.66 18.602-3.737 3.262-1.63 4.103-2.972 4.318-3.263-.215-.291-1.056-1.633-4.318-3.264-4.153-2.077-10.981-3.736-18.602-3.736zm22.92 7c.059.08.08.095.08 0 0-.096-.021-.08-.08 0zm-45.84 0c-.059-.08-.08-.096-.08 0 0 .095.021.08.08 0zm-.08 20.984v48.352c6.7-2.648 14.535-4.016 23-4.016s16.3 1.368 23 4.016v-48.352c-6.7 2.648-14.535 4.016-23 4.016s-16.3-1.368-23-4.016zM256 313c-7.62 0-14.449 1.66-18.602 3.736-3.262 1.632-4.103 2.973-4.318 3.264.215.291 1.056 1.632 4.318 3.264C241.551 325.34 248.38 327 256 327c7.62 0 14.449-1.66 18.602-3.736 3.262-1.632 4.103-2.973 4.318-3.264-.215-.291-1.056-1.632-4.318-3.264C270.449 314.66 263.62 313 256 313zm22.92 7c.059.08.08.096.08 0s-.021-.08-.08 0zm-45.84 0c-.059-.08-.08-.096-.08 0s.021.08.08 0zm-.08 20.984v45.87c6.7-2.649 14.535-4.016 23-4.016s16.3 1.367 23 4.016v-45.87c-6.7 2.648-14.535 4.016-23 4.016s-16.3-1.368-23-4.016zm23 59.854c-7.62 0-14.449 1.66-18.602 3.736-3.262 1.631-4.103 2.973-4.318 3.264.215.29 1.056 1.632 4.318 3.264 4.153 2.076 10.981 3.736 18.602 3.736 7.62 0 14.449-1.66 18.602-3.736 3.262-1.632 4.103-2.973 4.318-3.264-.215-.291-1.056-1.633-4.318-3.264-4.153-2.076-10.981-3.736-18.602-3.736zm22.92 7c.059.08.08.095.08 0 0-.096-.021-.08-.08 0zm-45.84 0c-.059-.08-.08-.096-.08 0 0 .095.021.08.08 0zM73 409v30h18.455c-2.78-4.422-4.455-9.52-4.455-15s1.676-10.578 4.455-15H73zm55 0c-7.013 0-13.194 2.204-17.227 5.229C106.74 417.253 105 420.615 105 424c0 3.385 1.74 6.747 5.773 9.771C114.806 436.796 120.987 439 128 439s13.194-2.204 17.227-5.229C149.26 430.747 151 427.385 151 424c0-3.385-1.74-6.747-5.773-9.771C141.194 411.204 135.013 409 128 409zm36.545 0c2.78 4.422 4.455 9.52 4.455 15s-1.676 10.578-4.455 15H215v-30h-50.455zM297 409v30h50.455c-2.78-4.422-4.455-9.52-4.455-15s1.676-10.578 4.455-15H297zm87 0c-7.013 0-13.194 2.204-17.227 5.229C362.74 417.253 361 420.615 361 424c0 3.385 1.74 6.747 5.773 9.771C370.806 436.796 376.987 439 384 439s13.194-2.204 17.227-5.229C405.26 430.747 407 427.385 407 424c0-3.385-1.74-6.747-5.773-9.771C397.194 411.204 391.013 409 384 409zm36.545 0c2.78 4.422 4.455 9.52 4.455 15s-1.676 10.578-4.455 15H439v-30h-18.455zM233 428.822v16.453l23 34.5 23-34.5v-16.453c-6.7 2.648-14.535 4.016-23 4.016s-16.3-1.368-23-4.016z' />
</svg>
</>
);
}
VikingHelmet.displayName = 'VikingHelmet';
export default VikingHelmet;

View File

@ -0,0 +1,9 @@
---
title: The Odin Project
superBlock: the-odin-project
certification: the-odin-project
---
## The Odin project
The Odin Project is one of those "What I wish I had when I was learning" resources. Not everyone has access to a computer science education or the funds to attend an intensive coding school and neither of those is right for everyone anyway. This project is designed to fill in the gap for people who are trying to hack it on their own but still want a high quality education.

View File

@ -0,0 +1,9 @@
---
title: The Odin Project
superBlock: the-odin-project
certification: the-odin-project
---
## The Odin project
Description is to be determined

View File

@ -0,0 +1,9 @@
---
title: The Odin Project
superBlock: the-odin-project
certification: the-odin-project
---
## The Odin project
Description is to be determined

View File

@ -210,16 +210,17 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
/>
</Fragment>
))}
{superBlock !== SuperBlocks.CodingInterviewPrep && (
<div>
<CertChallenge
certification={certification}
superBlock={superBlock}
title={title}
user={user}
/>
</div>
)}
{superBlock !== SuperBlocks.CodingInterviewPrep &&
superBlock !== SuperBlocks.TheOdinProject && (
<div>
<CertChallenge
certification={certification}
superBlock={superBlock}
title={title}
user={user}
/>
</div>
)}
</div>
{!isSignedIn && !signInLoading && (
<div>

View File

@ -9,7 +9,10 @@ enum SuperBlockI18nKeys {
// the key above is used to create the last word for superBlock titles used on
// the map and window. e.g. 'Certification' in Responsive Web Design
// Certification
const superBlocksWithoutLastWord = [SuperBlocks.CodingInterviewPrep];
const superBlocksWithoutLastWord = [
SuperBlocks.CodingInterviewPrep,
SuperBlocks.TheOdinProject
];
export function getSuperBlockTitleForMap(superBlock: SuperBlocks) {
const i18nSuperBlock = i18next.t(`intro:${superBlock}.title`);

View File

@ -42,8 +42,8 @@
"algorithms": "JavaScript",
"data-structures": "JavaScript",
"take-home-projects": "JavaScript",
"the-odin-project": "HTML-CSS",
"the-odin-project-projects": "HTML-CSS",
"top-learn-html-foundations": "HTML-CSS",
"top-build-a-recipe-project": "HTML-CSS",
"rosetta-code": "JavaScript",
"project-euler": "JavaScript",
"scientific-computing-with-python": "Python",

View File

@ -31,7 +31,8 @@ export enum SuperBlocks {
DataAnalysisPy = 'data-analysis-with-python',
InfoSec = 'information-security',
MachineLearningPy = 'machine-learning-with-python',
CodingInterviewPrep = 'coding-interview-prep'
CodingInterviewPrep = 'coding-interview-prep',
TheOdinProject = 'the-odin-project'
}
export const certIds = {

View File

@ -150,6 +150,7 @@ describe("'superBlockOrder' helper functions", () => {
SuperBlocks.MachineLearningPy,
SuperBlocks.CodingInterviewPrep,
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject,
SuperBlocks.RespWebDesign
];
expect(learnSuperBlocks).toStrictEqual(test);
@ -188,7 +189,8 @@ describe("'superBlockOrder' helper functions", () => {
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy,
SuperBlocks.CodingInterviewPrep,
SuperBlocks.JsAlgoDataStructNew
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
];
expect(notAuditedSuperBlocks).toStrictEqual(test);
expect(notAuditedSuperBlocks.length).toEqual(test.length);

View File

@ -78,7 +78,8 @@ export const defaultSuperBlockOrder: SuperBlocks[] = [
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy,
SuperBlocks.CodingInterviewPrep
SuperBlocks.CodingInterviewPrep,
SuperBlocks.TheOdinProject
];
/*
@ -124,7 +125,10 @@ export const superBlockOrder: SuperBlockOrder = {
SuperBlocks.CodingInterviewPrep
],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
},
[TranslationStates.NotAudited]: {
@ -173,7 +177,10 @@ export const superBlockOrder: SuperBlockOrder = {
SuperBlocks.CodingInterviewPrep
],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -216,7 +223,10 @@ export const superBlockOrder: SuperBlockOrder = {
SuperBlocks.CodingInterviewPrep
],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -259,7 +269,10 @@ export const superBlockOrder: SuperBlockOrder = {
SuperBlocks.CodingInterviewPrep
],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -301,7 +314,10 @@ export const superBlockOrder: SuperBlockOrder = {
[TranslationStates.NotAudited]: {
[SuperBlockStates.Current]: [],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -343,7 +359,10 @@ export const superBlockOrder: SuperBlockOrder = {
[TranslationStates.NotAudited]: {
[SuperBlockStates.Current]: [],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -384,7 +403,10 @@ export const superBlockOrder: SuperBlockOrder = {
[TranslationStates.NotAudited]: {
[SuperBlockStates.Current]: [SuperBlocks.CodingInterviewPrep],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -427,7 +449,10 @@ export const superBlockOrder: SuperBlockOrder = {
[TranslationStates.NotAudited]: {
[SuperBlockStates.Current]: [],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -471,7 +496,10 @@ export const superBlockOrder: SuperBlockOrder = {
SuperBlocks.CodingInterviewPrep
],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: []
}
}
@ -514,7 +542,10 @@ export const superBlockOrder: SuperBlockOrder = {
SuperBlocks.CodingInterviewPrep
],
[SuperBlockStates.New]: [],
[SuperBlockStates.Upcoming]: [SuperBlocks.JsAlgoDataStructNew],
[SuperBlockStates.Upcoming]: [
SuperBlocks.JsAlgoDataStructNew,
SuperBlocks.TheOdinProject
],
[SuperBlockStates.Legacy]: [SuperBlocks.RespWebDesign]
}
}

View File

@ -1,12 +1,11 @@
{
"name": "The Odin Project Projects",
"name": "TOP build a recipe project",
"isUpcomingChange": true,
"dashedName": "the-odin-project-projects",
"order": 6,
"order": 1,
"time": "",
"template": "",
"required": [],
"superBlock": "coding-interview-prep",
"superBlock": "the-odin-project",
"challengeOrder": [
[
"6391d1a4f7ac71efd0621380",

View File

@ -1,12 +1,11 @@
{
"name": "The Odin Project",
"name": "TOP Learn HTML Foundations",
"isUpcomingChange": true,
"dashedName": "the-odin-project",
"order": 5,
"order": 0,
"time": "",
"template": "",
"required": [],
"superBlock": "coding-interview-prep",
"superBlock": "the-odin-project",
"challengeOrder": [
[
"6374f208de18c50e48ba767b",

View File

@ -2,7 +2,7 @@
id: 6391d1a4f7ac71efd0621380
title: Build a Recipe Page Project
challengeType: 14
dashedName: project-create-a-recipe-page
dashedName: top-build-a-recipe-project
---
# --description--

View File

@ -120,7 +120,8 @@ const directoryToSuperblock = {
'13-relational-databases': 'relational-database',
'14-responsive-web-design-22': '2022/responsive-web-design',
'15-javascript-algorithms-and-data-structures-22':
'2022/javascript-algorithms-and-data-structures'
'2022/javascript-algorithms-and-data-structures',
'16-the-odin-project': 'the-odin-project'
};
function getSuperBlockFromDir(dir) {

View File

@ -39,7 +39,8 @@ const upcomingTest = {
[SuperBlocks.MachineLearningPy]: 10,
[SuperBlocks.CodingInterviewPrep]: 11,
[SuperBlocks.JsAlgoDataStructNew]: 12,
[SuperBlocks.RespWebDesign]: 13
[SuperBlocks.TheOdinProject]: 13,
[SuperBlocks.RespWebDesign]: 14
};
const espanolTest = {
@ -144,7 +145,7 @@ describe('getSuperOrder', () => {
if (process.env.SHOW_UPCOMING_CHANGES !== 'true') {
expect.assertions(13);
} else {
expect.assertions(14);
expect.assertions(15);
}
expect(getSuperOrder(SuperBlocks.RespWebDesignNew)).toBe(0);
@ -162,7 +163,8 @@ describe('getSuperOrder', () => {
if (process.env.SHOW_UPCOMING_CHANGES === 'true') {
expect(getSuperOrder(SuperBlocks.JsAlgoDataStructNew)).toBe(12);
expect(getSuperOrder(SuperBlocks.RespWebDesign)).toBe(13);
expect(getSuperOrder(SuperBlocks.TheOdinProject)).toBe(13);
expect(getSuperOrder(SuperBlocks.RespWebDesign)).toBe(14);
} else {
expect(getSuperOrder(SuperBlocks.RespWebDesign)).toBe(12);
}
@ -175,7 +177,7 @@ describe('getSuperBlockFromPath', () => {
);
it('handles all the directories in ./challenges/english', () => {
expect.assertions(15);
expect.assertions(16);
for (const directory of directories) {
expect(() => getSuperBlockFromDir(directory)).not.toThrow();
@ -183,7 +185,7 @@ describe('getSuperBlockFromPath', () => {
});
it("returns valid superblocks (or 'certifications') for all valid arguments", () => {
expect.assertions(15);
expect.assertions(16);
const superBlockPaths = directories.filter(x => x !== '00-certifications');

View File

@ -29,7 +29,8 @@ const superBlockFolderMap = {
'relational-database': '13-relational-database',
'2022/responsive-web-design': '14-responsive-web-design-22',
'2022/javascript-algorithms-and-data-structures':
'15-javascript-algorithms-and-data-structures-22'
'15-javascript-algorithms-and-data-structures-22',
'the-odin-project': '16-the-odin-project'
};
// These blocks are in the incorrect superblock. They should be moved but, for

View File

@ -54,5 +54,9 @@ export const superBlockList = [
{
name: 'JavaScript Algorithms and Data Structures (Beta)',
path: '15-javascript-algorithms-and-data-structures-22'
},
{
name: 'The Odin Project',
path: '16-the-odin-project'
}
];

View File

@ -17,7 +17,8 @@ export function getSuperBlockSubPath(superBlock: SuperBlocks): string {
[SuperBlocks.RelationalDb]: '13-relational-databases',
[SuperBlocks.RespWebDesignNew]: '14-responsive-web-design-22',
[SuperBlocks.JsAlgoDataStructNew]:
'15-javascript-algorithms-and-data-structures-22'
'15-javascript-algorithms-and-data-structures-22',
[SuperBlocks.TheOdinProject]: '16-the-odin-project'
};
return pathMap[superBlock];
}

View File

@ -82,10 +82,16 @@ if (envData.clientLocale == 'english' && !envData.showUpcomingChanges) {
const dashedNames = orderedSuperBlockInfo.map(
({ dashedName }) => dashedName
);
const isUpcoming = [
'2022/javascript-algorithms-and-data-structures',
'the-odin-project'
];
// TODO: this is a hack, we should have a single source of truth for the
// list of superblocks that are available.
const publicSuperBlockNames = Object.values(SuperBlocks).filter(
x => x !== '2022/javascript-algorithms-and-data-structures'
x => !isUpcoming.includes(x)
);
expect(dashedNames).toEqual(