diff --git a/src/components/Sidebar.js b/src/components/Sidebar.js
index 64fa2d446..7c63d437c 100644
--- a/src/components/Sidebar.js
+++ b/src/components/Sidebar.js
@@ -9,9 +9,13 @@ import './Sidebar.scss';
// recursively create navigation
const renderNav = (page, index) => (
-
- {page.displayName}
-
+ {page.url ? (
+
+ {page.displayName}
+
+ ) : (
+ {page.displayName}
+ )}
{page.children && {page.children.map(renderNav)}
}
);
diff --git a/src/pages/reference.js b/src/pages/reference.js
index a4bcc4bd9..7e7f3f9c8 100644
--- a/src/pages/reference.js
+++ b/src/pages/reference.js
@@ -1,64 +1,33 @@
import React, { useState } from 'react';
+import { useStaticQuery, graphql } from 'gatsby';
import Container from '../components/Container';
import Layout from '../components/Layout';
import Sidebar from '../components/Sidebar';
+import navFromEdges from '../utils/nav-from-edges';
// TODO: move this js file to same directory and update import
import '../templates/Reference.scss';
-// TODO: pull this in from Gatsby
-const pages = [
- { displayName: 'Overview', url: '' },
- {
- displayName: 'CLI',
- url: '',
- children: [
- { displayName: 'newrelic', url: '' },
- { displayName: 'nr1', url: '' },
- ],
- },
- { displayName: 'GraphQL', url: '' },
- {
- displayName: 'Applications',
- url: '',
- children: [
- { displayName: 'Component Library', url: '', active: true },
- { displayName: 'File structure', url: '' },
- ],
- },
- {
- displayName: 'Data Collectors',
- url: '',
- children: [
- { displayName: 'Custom Attributes', url: '' },
- { displayName: 'Custom Events', url: '' },
- { displayName: 'Open Telemetry', url: '' },
- { displayName: 'Telemetry SDK', url: '' },
- ],
- },
- {
- displayName: 'Automation',
- url: '',
- children: [
- { displayName: 'Cloud Formation Provider', url: '' },
- { displayName: 'Terraform Provider', url: '' },
- {
- displayName: 'Agent Deploy',
- url: '',
- children: [
- { displayName: 'Ansible', url: '' },
- { displayName: 'Chef', url: '' },
- { displayName: 'Puppet', url: '' },
- ],
- },
- ],
- },
-];
-
const Reference = () => {
const [isOpen, setIsOpen] = useState(false);
+ const data = useStaticQuery(graphql`
+ query {
+ allMarkdownRemark(limit: 1000) {
+ edges {
+ node {
+ frontmatter {
+ path
+ title
+ }
+ }
+ }
+ }
+ }
+ `);
+ const pages = navFromEdges(data.allMarkdownRemark.edges);
+
return (
diff --git a/src/utils/nav-from-edges.js b/src/utils/nav-from-edges.js
new file mode 100644
index 000000000..2505ae1a5
--- /dev/null
+++ b/src/utils/nav-from-edges.js
@@ -0,0 +1,100 @@
+/**
+ * Convert an object used for generating the tree into an object
+ * to be used in the UI.
+ *
+ * @param {Object} link - A link object that includes directories.
+ * @param {string} link.url - The local path to the page.
+ * @param {string} link.displayName - The title for the page.
+ * @return {Object} A link object with just a url and displayName.
+ */
+const linkWithoutDirs = (link) => ({
+ url: link.url,
+ displayName: link.displayName,
+});
+
+/**
+ * Creates a link object (including a list of directories) from an
+ * edge (generated by GraphQL).
+ *
+ * @param {Object} edge - A markdown edge.
+ * @return {Object} A link object that includes directories.
+ */
+const linkFromEdge = (edge) => {
+ const { path, title } = edge?.node?.frontmatter;
+ return {
+ url: path,
+ displayName: title,
+ dirs: path.split('/').slice(1),
+ };
+};
+
+/**
+ * Converts a slug into a displayName.
+ *
+ * @param {string} str - A slug-like string.
+ * @return {string} A displayName for use in the UI.
+ */
+const makeDisplayName = (str) =>
+ str
+ .split('-')
+ .map((word) => word.replace(/\b\w/g, (l) => l.toUpperCase()))
+ .join(' ');
+
+/**
+ * Generates an array of links for the UI. Each link can have an
+ * array of links below that. This function can call itself.
+ *
+ * TODO: do we need result?
+ *
+ * @param {Object[]} links - An array of links that are >= this level.
+ * @param {Object[]} [result] - The links to be returned.
+ * @param {number} [level=0] The nested level.
+ */
+const genTree = (links, result = [], level = 0) => {
+ const linksAtLevel = links.filter((link) => level === link.dirs.length - 1);
+
+ // if we have nothing below this, just return a flat list of links
+ if (linksAtLevel.length === links.length) {
+ return linksAtLevel.map(linkWithoutDirs);
+ }
+
+ // get all the directories at this level
+ const linksBelowLevel = links.filter((link) => level < link.dirs.length - 1);
+ const dirsAtLevel = linksBelowLevel.map((link) => link.dirs[level]);
+ const uniqueDirsAtLevel = [...new Set(dirsAtLevel)];
+
+ return uniqueDirsAtLevel.reduce((acc, dir) => {
+ const linksUnderDir = links.filter((link) => link.dirs[level] === dir);
+
+ // find the index page, or make a non-link item for this
+ const index = linksUnderDir.find(
+ (link) => link.dirs[level + 1] === 'index'
+ );
+
+ // get the children for this node
+ const childLinks = linksUnderDir.filter((link) => link !== index);
+
+ return [
+ ...acc,
+ {
+ ...(index
+ ? linkWithoutDirs(index)
+ : { displayName: makeDisplayName(dir) }),
+ children: genTree(childLinks, result, level + 1),
+ },
+ ];
+ }, []);
+};
+
+/**
+ * Given a list of edges, generates the navigation to be used in the UI.
+ *
+ * @param {Object[]} edges - An array of edge objects.
+ * @return {Object[]} An array of link objects.
+ */
+const getNavFromEdges = (edges) => {
+ const links = edges.map(linkFromEdge);
+ return genTree(links);
+};
+
+export default getNavFromEdges;