diff --git a/src/components/MDXContainer.js b/src/components/MDXContainer.js index 03c38ff28..9d063f2ab 100644 --- a/src/components/MDXContainer.js +++ b/src/components/MDXContainer.js @@ -13,6 +13,7 @@ import Intro from './Intro'; import Iframe from './Iframe'; import Tutorial from './Tutorial'; import TutorialStep from './TutorialStep'; +import Project from './Project'; import { MDXCodeBlock, Video } from '@newrelic/gatsby-theme-newrelic'; import styles from './MDXContainer.module.scss'; @@ -22,6 +23,7 @@ const components = { Step, Steps, Tutorial, + Project, TutorialStep, Caution, Important, diff --git a/src/components/Project.js b/src/components/Project.js new file mode 100644 index 000000000..35db72f07 --- /dev/null +++ b/src/components/Project.js @@ -0,0 +1,6 @@ +// Does not render. Will be used by the `Tutorial` component +const Project = () => { + return null; +}; + +export default Project; diff --git a/src/components/Tutorial.js b/src/components/Tutorial.js index 8f917acef..529048a33 100644 --- a/src/components/Tutorial.js +++ b/src/components/Tutorial.js @@ -1,10 +1,68 @@ -import React, { Children, cloneElement } from 'react'; +import { Children, cloneElement } from 'react'; import PropTypes from 'prop-types'; import parseCodeBlockProps from '../utils/parseCodeBlockProps'; import { isCodeBlock, isShellCommand } from '../utils/codeBlock'; const Tutorial = ({ children }) => { - const initialState = Children.toArray(children) + children = Children.toArray(children); + + const initialState = + children[0].props.mdxType === 'Project' + ? parseFileInfoFromConfig(children[0]) + : parseFileInfoFromChildren(children); + + return children + .filter((child) => child.props.mdxType === 'TutorialStep') + .reduce((steps, stepElement, idx, arr) => { + const codeBlock = Children.toArray(stepElement.props.children).find( + (child) => isCodeBlock(child) && !isShellCommand(child) + ); + + if (!codeBlock) { + return [ + ...steps, + cloneElement(stepElement, { index: idx, totalSteps: arr.length }), + ]; + } + + const previousStep = + idx === 0 + ? new Map(initialState) + : new Map(steps[idx - 1].props.step || initialState); + + const { fileName, code, language } = parseCodeBlockProps(codeBlock); + + return [ + ...steps, + cloneElement(stepElement, { + initialSelectedFile: fileName, + step: previousStep.set(fileName, { code, language }), + index: idx, + totalSteps: arr.length, + children: Children.toArray(stepElement.props.children).filter( + (child) => isShellCommand(child) || !isCodeBlock(child) + ), + }), + ]; + }, []); +}; + +Tutorial.propTypes = { + children: PropTypes.node, +}; + +const parseFileInfoFromConfig = (configElement) => { + return Children.toArray(configElement.props.children) + .filter((child) => isCodeBlock(child) && !isShellCommand(child)) + .reduce((map, child) => { + const { code, fileName, language } = parseCodeBlockProps(child); + + return map.has(fileName) ? map : map.set(fileName, { code, language }); + }, new Map()); +}; + +const parseFileInfoFromChildren = (children) => { + return children .flatMap((child) => Children.toArray(child.props.children)) .filter((child) => isCodeBlock(child) && !isShellCommand(child)) .reduce((map, child) => { @@ -14,40 +72,6 @@ const Tutorial = ({ children }) => { ? map : map.set(fileName, { code: '', language }); }, new Map()); - - return Children.toArray(children).reduce((steps, stepElement, idx, arr) => { - const codeBlock = Children.toArray(stepElement.props.children).find( - (child) => isCodeBlock(child) && !isShellCommand(child) - ); - - if (!codeBlock) { - return [...steps, stepElement]; - } - - const previousStep = - idx === 0 - ? new Map(initialState) - : new Map(steps[idx - 1].props.step || initialState); - - const { fileName, code, language } = parseCodeBlockProps(codeBlock); - - return [ - ...steps, - cloneElement(stepElement, { - initialSelectedFile: fileName, - step: previousStep.set(fileName, { code, language }), - index: idx, - totalSteps: arr.length, - children: Children.toArray(stepElement.props.children).filter( - (child) => isShellCommand(child) || !isCodeBlock(child) - ), - }), - ]; - }, []); -}; - -Tutorial.propTypes = { - children: PropTypes.node, }; export default Tutorial; diff --git a/src/markdown-pages/build-apps/map-pageviews-by-region.mdx b/src/markdown-pages/build-apps/map-pageviews-by-region.mdx index 050d555f7..44841105a 100644 --- a/src/markdown-pages/build-apps/map-pageviews-by-region.mdx +++ b/src/markdown-pages/build-apps/map-pageviews-by-region.mdx @@ -75,6 +75,23 @@ If you don't have any results at this point, ensure your query doesn't have any + + +```jsx fileName=pageview-app-nerdlet/index.js +import React from 'react'; + +export default class PageViewApp extends React.Component { + render() { + return

Hello, pageview-app-nerdlet Nerdlet!

; + } +} +``` + +```css fileName=pageview-app-nerdlet/styles.scss +``` + +
+ To get started, create a new Nerdpack, and serve it up to New Relic from your local development environment: @@ -109,7 +126,15 @@ When you select the launcher, you see a `Hello` message. For the purposes of this exercise and for your convenience, hard code your account ID. In the `pageview-app-nerdlet` directory, in the `index.js` file, add this code between the `import` and `export` lines. ([Read about finding your account ID here](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id)). ```jsx fileName=pageview-app-nerdlet/index.js -const accountId = [Replace with your account ID]; +import React from 'react'; + +const accountId = 0; // Replace with your account ID + +export default class PageViewApp extends React.Component { + render() { + return

Hello, pageview-app-nerdlet Nerdlet!

; + } +} ```
@@ -119,7 +144,16 @@ const accountId = [Replace with your account ID]; To show your data in a table chart, import the [`TableChart` component](/client-side-sdk/index.html#charts/TableChart) from New Relic One. To do so, in `index.js`, add this code under `import React`. ```jsx fileName=pageview-app-nerdlet/index.js +import React from 'react'; import { TableChart } from 'nr1'; + +const accountId = 0; // Replace with your account ID + +export default class PageViewApp extends React.Component { + render() { + return

Hello, pageview-app-nerdlet Nerdlet!

; + } +} ``` @@ -129,6 +163,11 @@ import { TableChart } from 'nr1'; To add a table with a single row, in the `index.js` file, replace this line with this `export` code: ```jsx fileName=pageview-app-nerdlet/index.js +import React from 'react'; +import { TableChart } from 'nr1'; + +const accountId = 0; // Replace with your account ID + export default class PageViewApp extends React.Component { render() { return ( @@ -149,7 +188,7 @@ You can use standard CSS to customize the look of your components. In the `styles.scss` file, add this CSS. Feel free to customize this CSS to your taste. -```css fileName=styles.scss +```css fileName=pageview-app-nerdlet/styles.scss .container { width: 100%; height: 99vh; @@ -175,12 +214,27 @@ Now that you've got a table, you can drop a `TableChart` populated with data fro Put this code into the `row` div. ```jsx fileName=pageview-app-nerdlet/index.js - +import React from 'react'; +import { TableChart } from 'nr1'; + +const accountId = 0; // Replace with your account ID + +export default class PageViewApp extends React.Component { + render() { + return ( +
+
+ +
+
+ ); + } +} ``` Go to New Relic One and click your app to see your data in the table. (You might need to serve your app to New Relic again.)