fix(description): Adjust for new description format
This commit is contained in:
@ -26,13 +26,6 @@ export default function settingsController(app) {
|
|||||||
createValidatorErrorHandler(alertTypes.danger),
|
createValidatorErrorHandler(alertTypes.danger),
|
||||||
updateMyCurrentChallenge
|
updateMyCurrentChallenge
|
||||||
);
|
);
|
||||||
api.post(
|
|
||||||
'/update-my-current-challenge',
|
|
||||||
ifNoUser401,
|
|
||||||
updateMyCurrentChallengeValidators,
|
|
||||||
createValidatorErrorHandler(alertTypes.danger),
|
|
||||||
updateMyCurrentChallenge
|
|
||||||
);
|
|
||||||
api.post('/update-my-portfolio', ifNoUser401, updateMyPortfolio);
|
api.post('/update-my-portfolio', ifNoUser401, updateMyPortfolio);
|
||||||
api.post('/update-my-projects', ifNoUser401, updateMyProjects);
|
api.post('/update-my-projects', ifNoUser401, updateMyProjects);
|
||||||
api.post(
|
api.post(
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import helmet from 'helmet';
|
import helmet from 'helmet';
|
||||||
|
|
||||||
|
import { homeLocation } from '../../../config/env';
|
||||||
|
|
||||||
let trusted = [
|
let trusted = [
|
||||||
"'self'",
|
"'self'",
|
||||||
'https://search.freecodecamp.org',
|
'https://search.freecodecamp.org',
|
||||||
'https://www.freecodecamp.rocks',
|
homeLocation,
|
||||||
'https://api.freecodecamp.rocks',
|
|
||||||
'https://' + process.env.AUTH0_DOMAIN
|
'https://' + process.env.AUTH0_DOMAIN
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -12,9 +13,7 @@ const host = process.env.HOST || 'localhost';
|
|||||||
const port = process.env.SYNC_PORT || '3000';
|
const port = process.env.SYNC_PORT || '3000';
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
trusted = trusted.concat([
|
trusted = trusted.concat([`ws://${host}:${port}`, 'http://localhost:8000']);
|
||||||
`ws://${host}:${port}`
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function csp() {
|
export default function csp() {
|
||||||
@ -73,11 +72,9 @@ export default function csp() {
|
|||||||
'*',
|
'*',
|
||||||
'data:'
|
'data:'
|
||||||
],
|
],
|
||||||
mediaSrc: [
|
mediaSrc: ['*.bitly.com', '*.amazonaws.com', '*.twitter.com'].concat(
|
||||||
'*.bitly.com',
|
trusted
|
||||||
'*.amazonaws.com',
|
),
|
||||||
'*.twitter.com'
|
|
||||||
].concat(trusted),
|
|
||||||
frameSrc: [
|
frameSrc: [
|
||||||
'*.gitter.im',
|
'*.gitter.im',
|
||||||
'*.gitter.im https:',
|
'*.gitter.im https:',
|
||||||
|
@ -22,7 +22,7 @@ export const ChallengeNode = PropTypes.shape({
|
|||||||
block: PropTypes.string,
|
block: PropTypes.string,
|
||||||
challengeType: PropTypes.number,
|
challengeType: PropTypes.number,
|
||||||
dashedName: PropTypes.string,
|
dashedName: PropTypes.string,
|
||||||
description: PropTypes.arrayOf(PropTypes.string),
|
description: PropTypes.string,
|
||||||
files: PropTypes.shape({
|
files: PropTypes.shape({
|
||||||
indexhtml: FileType,
|
indexhtml: FileType,
|
||||||
indexjs: FileType
|
indexjs: FileType
|
||||||
@ -34,6 +34,7 @@ export const ChallengeNode = PropTypes.shape({
|
|||||||
guideUrl: PropTypes.string,
|
guideUrl: PropTypes.string,
|
||||||
head: PropTypes.arrayOf(PropTypes.string),
|
head: PropTypes.arrayOf(PropTypes.string),
|
||||||
challengeOrder: PropTypes.number,
|
challengeOrder: PropTypes.number,
|
||||||
|
instructions: PropTypes.string,
|
||||||
isBeta: PropTypes.bool,
|
isBeta: PropTypes.bool,
|
||||||
isComingSoon: PropTypes.bool,
|
isComingSoon: PropTypes.bool,
|
||||||
isLocked: PropTypes.bool,
|
isLocked: PropTypes.bool,
|
||||||
|
@ -41,7 +41,7 @@ const reduxFormPropTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
description: PropTypes.arrayOf(PropTypes.string),
|
description: PropTypes.string,
|
||||||
executeChallenge: PropTypes.func.isRequired,
|
executeChallenge: PropTypes.func.isRequired,
|
||||||
id: PropTypes.string,
|
id: PropTypes.string,
|
||||||
output: PropTypes.string,
|
output: PropTypes.string,
|
||||||
@ -126,7 +126,8 @@ export class BackEnd extends Component {
|
|||||||
challengeNode: {
|
challengeNode: {
|
||||||
fields: { blockName, slug },
|
fields: { blockName, slug },
|
||||||
title,
|
title,
|
||||||
description
|
description,
|
||||||
|
instructions
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
output,
|
output,
|
||||||
@ -145,7 +146,10 @@ export class BackEnd extends Component {
|
|||||||
<Spacer />
|
<Spacer />
|
||||||
<div>
|
<div>
|
||||||
<ChallengeTitle>{blockNameTitle}</ChallengeTitle>
|
<ChallengeTitle>{blockNameTitle}</ChallengeTitle>
|
||||||
<ChallengeDescription description={description} />
|
<ChallengeDescription
|
||||||
|
description={description}
|
||||||
|
instructions={instructions}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Form
|
<Form
|
||||||
@ -200,6 +204,7 @@ export const query = graphql`
|
|||||||
title
|
title
|
||||||
guideUrl
|
guideUrl
|
||||||
description
|
description
|
||||||
|
instructions
|
||||||
challengeType
|
challengeType
|
||||||
fields {
|
fields {
|
||||||
blockName
|
blockName
|
||||||
|
@ -177,6 +177,7 @@ class ShowClassic extends Component {
|
|||||||
fields: { blockName, slug },
|
fields: { blockName, slug },
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
instructions,
|
||||||
videoUrl
|
videoUrl
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -227,6 +228,7 @@ class ShowClassic extends Component {
|
|||||||
className='full-height'
|
className='full-height'
|
||||||
description={description}
|
description={description}
|
||||||
guideUrl={createGuideUrl(slug)}
|
guideUrl={createGuideUrl(slug)}
|
||||||
|
instructions={instructions}
|
||||||
section={dasherize(blockName)}
|
section={dasherize(blockName)}
|
||||||
title={blockNameTitle}
|
title={blockNameTitle}
|
||||||
videoUrl={videoUrl}
|
videoUrl={videoUrl}
|
||||||
@ -271,6 +273,7 @@ export const query = graphql`
|
|||||||
challengeNode(fields: { slug: { eq: $slug } }) {
|
challengeNode(fields: { slug: { eq: $slug } }) {
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
|
instructions
|
||||||
challengeType
|
challengeType
|
||||||
videoUrl
|
videoUrl
|
||||||
fields {
|
fields {
|
||||||
|
@ -1,44 +1,29 @@
|
|||||||
import React from 'react';
|
import React, { Fragment } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Col, Row } from '@freecodecamp/react-bootstrap';
|
import { Col, Row } from '@freecodecamp/react-bootstrap';
|
||||||
import { descriptionRegex } from '../../../../utils';
|
|
||||||
|
|
||||||
import './challenge-description.css';
|
import './challenge-description.css';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
description: PropTypes.arrayOf(PropTypes.string),
|
description: PropTypes.string,
|
||||||
|
instructions: PropTypes.string,
|
||||||
section: PropTypes.string
|
section: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
function renderDescription(description) {
|
function ChallengeDescription({ description, instructions, section }) {
|
||||||
if (!Array.isArray(description)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return description.map((line, index) => {
|
|
||||||
if (descriptionRegex.test(line)) {
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
dangerouslySetInnerHTML={{ __html: line }}
|
|
||||||
key={line.slice(-6) + index}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<p
|
|
||||||
className='wrappable'
|
|
||||||
dangerouslySetInnerHTML={{ __html: line }}
|
|
||||||
key={line.slice(-6) + index}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function ChallengeDescription({ description, section }) {
|
|
||||||
// TODO: Remove bootstrap
|
|
||||||
return (
|
return (
|
||||||
<Row>
|
<Row>
|
||||||
<Col className={`challenge-instructions ${section}`} xs={12}>
|
<Col className={`challenge-instructions ${section}`} xs={12}>
|
||||||
{renderDescription(description)}
|
<div dangerouslySetInnerHTML={{ __html: description }} />
|
||||||
|
{instructions ? (
|
||||||
|
<Fragment>
|
||||||
|
<hr />
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: instructions }} />
|
||||||
|
<hr />
|
||||||
|
</Fragment>
|
||||||
|
) : (
|
||||||
|
<hr />
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { Component } from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ReactDom from 'react-dom';
|
import ReactDom from 'react-dom';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
@ -29,16 +29,17 @@ const mapDispatchToProps = dispatch =>
|
|||||||
const MathJax = global.MathJax;
|
const MathJax = global.MathJax;
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
description: PropTypes.arrayOf(PropTypes.string),
|
description: PropTypes.string,
|
||||||
guideUrl: PropTypes.string,
|
guideUrl: PropTypes.string,
|
||||||
initConsole: PropTypes.func.isRequired,
|
initConsole: PropTypes.func.isRequired,
|
||||||
|
instructions: PropTypes.string,
|
||||||
section: PropTypes.string,
|
section: PropTypes.string,
|
||||||
tests: PropTypes.arrayOf(PropTypes.object),
|
tests: PropTypes.arrayOf(PropTypes.object),
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
videoUrl: PropTypes.string
|
videoUrl: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
export class SidePanel extends PureComponent {
|
export class SidePanel extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.bindTopDiv = this.bindTopDiv.bind(this);
|
this.bindTopDiv = this.bindTopDiv.bind(this);
|
||||||
@ -84,6 +85,7 @@ export class SidePanel extends PureComponent {
|
|||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
|
instructions,
|
||||||
guideUrl,
|
guideUrl,
|
||||||
tests,
|
tests,
|
||||||
section,
|
section,
|
||||||
@ -95,7 +97,7 @@ export class SidePanel extends PureComponent {
|
|||||||
<Spacer />
|
<Spacer />
|
||||||
<div>
|
<div>
|
||||||
<ChallengeTitle>{title}</ChallengeTitle>
|
<ChallengeTitle>{title}</ChallengeTitle>
|
||||||
<ChallengeDescription description={description} section={section} />
|
<ChallengeDescription description={description} instructions={instructions} section={section} />
|
||||||
</div>
|
</div>
|
||||||
<ToolPanel guideUrl={guideUrl} videoUrl={videoUrl} />
|
<ToolPanel guideUrl={guideUrl} videoUrl={videoUrl} />
|
||||||
<TestSuite tests={tests} />
|
<TestSuite tests={tests} />
|
||||||
|
@ -1,37 +1,24 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import ChallengeTitle from '../components/Challenge-Title';
|
import ChallengeTitle from '../components/Challenge-Title';
|
||||||
import Spacer from '../../../components/helpers/Spacer';
|
import Spacer from '../../../components/helpers/Spacer';
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
description: PropTypes.arrayOf(PropTypes.string),
|
description: PropTypes.string,
|
||||||
isCompleted: PropTypes.bool,
|
isCompleted: PropTypes.bool,
|
||||||
isSignedIn: PropTypes.bool,
|
isSignedIn: PropTypes.bool,
|
||||||
title: PropTypes.string
|
title: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class SidePanel extends PureComponent {
|
export default function SidePanel({ title, description, isCompleted }) {
|
||||||
renderDescription(title = '', description = []) {
|
|
||||||
return description.map((line, index) => (
|
|
||||||
<li
|
|
||||||
className='step-text wrappable'
|
|
||||||
dangerouslySetInnerHTML={{ __html: line }}
|
|
||||||
key={title.slice(6) + index}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { title, description, isCompleted } = this.props;
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<ChallengeTitle isCompleted={isCompleted}>{title}</ChallengeTitle>
|
<ChallengeTitle isCompleted={isCompleted}>{title}</ChallengeTitle>
|
||||||
<ul>{this.renderDescription(title, description)}</ul>
|
<div dangerouslySetInnerHTML={{ __html: description }} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
SidePanel.displayName = 'ProjectSidePanel';
|
SidePanel.displayName = 'ProjectSidePanel';
|
||||||
SidePanel.propTypes = propTypes;
|
SidePanel.propTypes = propTypes;
|
||||||
|
@ -39,7 +39,6 @@ class GuideArticle extends Component {
|
|||||||
},
|
},
|
||||||
pageContext: { meta }
|
pageContext: { meta }
|
||||||
} = this.props;
|
} = this.props;
|
||||||
console.log(title);
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Helmet>
|
<Helmet>
|
||||||
|
Reference in New Issue
Block a user