mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-03-27 02:01:02 -04:00
feat(challenge-editor): make work in gitpod (#46784)
* feat(challenge-editor): make work in gitpod * gitpod: make chal-editor ports public * refactor: use .env files to set variables Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
@@ -14,6 +14,10 @@ ports:
|
||||
onOpen: ignore
|
||||
- port: 9230 # client node debug
|
||||
onOpen: ignore
|
||||
- port: 3200 # challenge editor api
|
||||
visibility: public
|
||||
- port: 3300 # challenge editor client
|
||||
visibility: public
|
||||
|
||||
tasks:
|
||||
- before: |
|
||||
@@ -22,6 +26,8 @@ tasks:
|
||||
export HOME_LOCATION=$(gp url 8000)
|
||||
export API_LOCATION=$(gp url 3000)
|
||||
export CYPRESS_BASE_URL=$(gp url 8000)
|
||||
export REACT_APP_CHALLENGE_EDITOR_API_LOCATION=$(gp url 3200)
|
||||
export CHALLENGE_EDITOR_CLIENT_LOCATION=$(gp url 3300)
|
||||
' >> ~/.bashrc;
|
||||
exit;
|
||||
|
||||
|
||||
21
package-lock.json
generated
21
package-lock.json
generated
@@ -53736,6 +53736,7 @@
|
||||
"tools/challenge-editor/api": {
|
||||
"name": "@freecodecamp/challenge-editor",
|
||||
"version": "1.0.0",
|
||||
"hasInstallScript": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"cors": "2.8.5",
|
||||
@@ -53745,12 +53746,23 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "4.17.13",
|
||||
"dotenv": "16.0.1",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
},
|
||||
"tools/challenge-editor/api/node_modules/dotenv": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
|
||||
"integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"tools/challenge-editor/client": {
|
||||
"name": "@freecodecamp/challenge-editor-client",
|
||||
"version": "0.1.0",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "5.16.4",
|
||||
"@testing-library/react": "12.1.5",
|
||||
@@ -56066,10 +56078,19 @@
|
||||
"requires": {
|
||||
"@types/express": "4.17.13",
|
||||
"cors": "2.8.5",
|
||||
"dotenv": "16.0.1",
|
||||
"express": "4.18.1",
|
||||
"gray-matter": "4.0.3",
|
||||
"ts-node": "10.8.2",
|
||||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"dotenv": {
|
||||
"version": "16.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
|
||||
"integrity": "sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"@freecodecamp/challenge-editor-client": {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"private": true,
|
||||
"description": "Editor to help with new challenge structure",
|
||||
"scripts": {
|
||||
"start": "ts-node server.ts"
|
||||
"start": "ts-node server.ts",
|
||||
"postinstall": "cp ./sample.env ./.env"
|
||||
},
|
||||
"author": "freeCodeCamp",
|
||||
"license": "BSD-3-Clause",
|
||||
@@ -16,6 +17,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "4.17.13",
|
||||
"dotenv": "16.0.1",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
||||
|
||||
1
tools/challenge-editor/api/sample.env
Normal file
1
tools/challenge-editor/api/sample.env
Normal file
@@ -0,0 +1 @@
|
||||
CHALLENGE_EDITOR_CLIENT_LOCATION=http://localhost:3300
|
||||
@@ -1,3 +1,6 @@
|
||||
import * as dotenv from 'dotenv';
|
||||
dotenv.config();
|
||||
|
||||
import cors from 'cors';
|
||||
import express from 'express';
|
||||
import { blockRoute } from './routes/blockRoute';
|
||||
@@ -11,7 +14,7 @@ const app = express();
|
||||
|
||||
app.use(
|
||||
cors({
|
||||
origin: 'http://localhost:3300'
|
||||
origin: process.env.CHALLENGE_EDITOR_CLIENT_LOCATION
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
@@ -18,7 +18,8 @@
|
||||
"lint": "eslint src",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
"eject": "react-scripts eject",
|
||||
"postinstall": "cp ./sample.env ./.env"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
1
tools/challenge-editor/client/sample.env
Normal file
1
tools/challenge-editor/client/sample.env
Normal file
@@ -0,0 +1 @@
|
||||
REACT_APP_CHALLENGE_EDITOR_API_LOCATION=http://localhost:3200
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { ChallengeData } from '../../../interfaces/ChallengeData';
|
||||
import { API_LOCATION } from '../../utils/handleRequest';
|
||||
import './Block.css';
|
||||
|
||||
const Block = () => {
|
||||
@@ -16,7 +17,7 @@ const Block = () => {
|
||||
|
||||
const fetchData = () => {
|
||||
setLoading(true);
|
||||
fetch(`http://localhost:3200/${params.superblock}/${params.block}`)
|
||||
fetch(`${API_LOCATION}/${params.superblock}/${params.block}`)
|
||||
.then(res => res.json() as Promise<ChallengeData[]>)
|
||||
.then(
|
||||
superblocks => {
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
import React, { useState } from 'react';
|
||||
import { BlockRequiredProps } from '../../../interfaces/PropTypes';
|
||||
import { handleRequest } from '../../utils/handleRequest';
|
||||
import { API_LOCATION, handleRequest } from '../../utils/handleRequest';
|
||||
|
||||
const CreateEmptySteps = ({ superblock, block }: BlockRequiredProps) => {
|
||||
const [num, setNum] = useState(0);
|
||||
|
||||
const click = handleRequest(() =>
|
||||
fetch(
|
||||
`http://localhost:3200/${superblock}/${block}/_tools/create-empty-steps`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ num })
|
||||
}
|
||||
)
|
||||
fetch(`${API_LOCATION}/${superblock}/${block}/_tools/create-empty-steps`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ num })
|
||||
})
|
||||
);
|
||||
|
||||
const changeNum = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import React from 'react';
|
||||
import { BlockRequiredProps } from '../../../interfaces/PropTypes';
|
||||
import { handleRequest } from '../../utils/handleRequest';
|
||||
import { API_LOCATION, handleRequest } from '../../utils/handleRequest';
|
||||
|
||||
const CreateNextStep = ({ superblock, block }: BlockRequiredProps) => {
|
||||
const click = handleRequest(() =>
|
||||
fetch(
|
||||
`http://localhost:3200/${superblock}/${block}/_tools/create-next-step`,
|
||||
{
|
||||
method: 'POST'
|
||||
}
|
||||
)
|
||||
fetch(`${API_LOCATION}/${superblock}/${block}/_tools/create-next-step`, {
|
||||
method: 'POST'
|
||||
})
|
||||
);
|
||||
|
||||
return <button onClick={click}>Create Next Step</button>;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { BlockRequiredProps } from '../../../interfaces/PropTypes';
|
||||
import { handleRequest } from '../../utils/handleRequest';
|
||||
import { API_LOCATION, handleRequest } from '../../utils/handleRequest';
|
||||
|
||||
const DeleteStep = ({ superblock, block }: BlockRequiredProps) => {
|
||||
const [num, setNum] = useState(0);
|
||||
|
||||
const click = handleRequest(() =>
|
||||
fetch(`http://localhost:3200/${superblock}/${block}/_tools/delete-step`, {
|
||||
fetch(`${API_LOCATION}/${superblock}/${block}/_tools/delete-step`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import React, { useState } from 'react';
|
||||
import { BlockRequiredProps } from '../../../interfaces/PropTypes';
|
||||
import { handleRequest } from '../../utils/handleRequest';
|
||||
import { API_LOCATION, handleRequest } from '../../utils/handleRequest';
|
||||
|
||||
const InsertStep = ({ superblock, block }: BlockRequiredProps) => {
|
||||
const [num, setNum] = useState(0);
|
||||
|
||||
const click = handleRequest(() =>
|
||||
fetch(`http://localhost:3200/${superblock}/${block}/_tools/insert-step`, {
|
||||
fetch(`${API_LOCATION}/${superblock}/${block}/_tools/insert-step`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { ChallengeContentRequiredProps } from '../../../interfaces/PropTypes';
|
||||
import { handleRequest } from '../../utils/handleRequest';
|
||||
import { API_LOCATION, handleRequest } from '../../utils/handleRequest';
|
||||
|
||||
const SaveChallenge = ({
|
||||
superblock,
|
||||
@@ -9,7 +9,7 @@ const SaveChallenge = ({
|
||||
content
|
||||
}: ChallengeContentRequiredProps) => {
|
||||
const click = handleRequest(() =>
|
||||
fetch(`http://localhost:3200/${superblock}/${block}/${challenge}`, {
|
||||
fetch(`${API_LOCATION}/${superblock}/${block}/${challenge}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
import React from 'react';
|
||||
import { BlockRequiredProps } from '../../../interfaces/PropTypes';
|
||||
import { handleRequest } from '../../utils/handleRequest';
|
||||
import { API_LOCATION, handleRequest } from '../../utils/handleRequest';
|
||||
|
||||
const UpdateStepTitles = ({ superblock, block }: BlockRequiredProps) => {
|
||||
const click = handleRequest(() =>
|
||||
fetch(
|
||||
`http://localhost:3200/${superblock}/${block}/_tools/update-step-titles`,
|
||||
{
|
||||
method: 'POST'
|
||||
}
|
||||
)
|
||||
fetch(`${API_LOCATION}/${superblock}/${block}/_tools/update-step-titles`, {
|
||||
method: 'POST'
|
||||
})
|
||||
);
|
||||
|
||||
return <button onClick={click}>Reorder Steps</button>;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { Link, useParams } from 'react-router-dom';
|
||||
import { ChallengeContent } from '../../../interfaces/ChallengeContent';
|
||||
import SaveChallenge from '../buttons/SaveChallenge';
|
||||
import './Editor.css';
|
||||
import { API_LOCATION } from '../../utils/handleRequest';
|
||||
|
||||
const Editor = () => {
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
@@ -35,7 +36,7 @@ const Editor = () => {
|
||||
const fetchData = () => {
|
||||
setLoading(true);
|
||||
fetch(
|
||||
`http://localhost:3200/${params.superblock}/${params.block}/${params.challenge}`
|
||||
`${API_LOCATION}/${params.superblock}/${params.block}/${params.challenge}`
|
||||
)
|
||||
.then(res => res.json() as Promise<ChallengeContent>)
|
||||
.then(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { SuperBlock } from '../../../interfaces/SuperBlock';
|
||||
import { API_LOCATION } from '../../utils/handleRequest';
|
||||
|
||||
const Landing = () => {
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
@@ -13,7 +14,7 @@ const Landing = () => {
|
||||
|
||||
const fetchData = () => {
|
||||
setLoading(true);
|
||||
fetch('http://localhost:3200/')
|
||||
fetch(API_LOCATION)
|
||||
.then(res => res.json() as Promise<SuperBlock[]>)
|
||||
.then(
|
||||
superblocks => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Link, useParams } from 'react-router-dom';
|
||||
import { Block } from '../../../interfaces/Block';
|
||||
import { API_LOCATION } from '../../utils/handleRequest';
|
||||
|
||||
const SuperBlock = () => {
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
@@ -15,7 +16,7 @@ const SuperBlock = () => {
|
||||
|
||||
const fetchData = () => {
|
||||
setLoading(true);
|
||||
fetch(`http://localhost:3200/${params.superblock}`)
|
||||
fetch(`${API_LOCATION}/${params.superblock}`)
|
||||
.then(res => res.json() as Promise<Block[]>)
|
||||
.then(
|
||||
blocks => {
|
||||
|
||||
@@ -4,3 +4,6 @@ export const handleRequest = (makeRequest: () => Promise<Response>) => () => {
|
||||
.then(data => alert(JSON.stringify(data)))
|
||||
.catch(err => console.error(err));
|
||||
};
|
||||
|
||||
export const API_LOCATION = process.env
|
||||
.REACT_APP_CHALLENGE_EDITOR_API_LOCATION as string;
|
||||
|
||||
Reference in New Issue
Block a user