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:
Shaun Hamilton
2022-07-08 10:25:36 +01:00
committed by GitHub
parent 066c024327
commit cc7f584b96
18 changed files with 71 additions and 38 deletions

View File

@@ -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
View File

@@ -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": {

View File

@@ -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"
}
}

View File

@@ -0,0 +1 @@
CHALLENGE_EDITOR_CLIENT_LOCATION=http://localhost:3300

View File

@@ -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
})
);

View File

@@ -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": [

View File

@@ -0,0 +1 @@
REACT_APP_CHALLENGE_EDITOR_API_LOCATION=http://localhost:3200

View File

@@ -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 => {

View File

@@ -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>) => {

View File

@@ -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>;

View File

@@ -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'

View File

@@ -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'

View File

@@ -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'

View File

@@ -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>;

View File

@@ -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(

View File

@@ -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 => {

View File

@@ -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 => {

View File

@@ -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;