Skip to content

Commit a8454d3

Browse files
committed
feat: add logic for adding next page
1 parent d2b7b2c commit a8454d3

File tree

11 files changed

+213
-10
lines changed

11 files changed

+213
-10
lines changed

app/[[...path]]/page.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {PlatformContent} from 'sentry-docs/components/platformContent';
1313
import {
1414
getCurrentPlatformOrGuide,
1515
getDocsRootNode,
16+
getNextNode,
1617
nodeForPath,
1718
} from 'sentry-docs/docTree';
1819
import {isDeveloperDocs} from 'sentry-docs/isDeveloperDocs';
@@ -42,7 +43,11 @@ export const dynamic = 'force-static';
4243

4344
const mdxComponentsWithWrapper = mdxComponents(
4445
{Include, PlatformContent},
45-
({children, frontMatter}) => <DocPage frontMatter={frontMatter}>{children}</DocPage>
46+
({children, frontMatter, nextPage}) => (
47+
<DocPage frontMatter={frontMatter} nextPage={nextPage}>
48+
{children}
49+
</DocPage>
50+
)
4651
);
4752

4853
function MDXLayoutRenderer({mdxSource, ...rest}) {
@@ -95,6 +100,10 @@ export default async function Page({params}: {params: {path?: string[]}}) {
95100
}
96101

97102
const pageNode = nodeForPath(rootNode, params.path);
103+
const nextNode = pageNode ? getNextNode(pageNode) : undefined;
104+
const nextPage = nextNode
105+
? {path: nextNode.path, title: nextNode.frontmatter.title}
106+
: undefined;
98107

99108
if (!pageNode) {
100109
// eslint-disable-next-line no-console
@@ -122,7 +131,11 @@ export default async function Page({params}: {params: {path?: string[]}}) {
122131

123132
// pass frontmatter tree into sidebar, rendered page + fm into middle, headers into toc.
124133
return (
125-
<MDXLayoutRenderer mdxSource={mdxSource} frontMatter={{...frontMatter, versions}} />
134+
<MDXLayoutRenderer
135+
mdxSource={mdxSource}
136+
frontMatter={{...frontMatter, versions}}
137+
nextPage={nextPage}
138+
/>
126139
);
127140
}
128141

docs/account/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Account Settings
3-
sidebar_order: 400
3+
sidebar_order: 10
44
description: "Learn about Sentry's user settings and auth tokens."
55
---
66

docs/api/index.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: API Reference
3+
sidebar_order: 60
34
---
45

56
The Sentry web API is used to access the Sentry platform programmatically. You can use the APIs to manage account-level resources, like organizations and teams, as well as manage and export data.

docs/cli/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "Sentry CLI"
3-
sidebar_order: 4000
3+
sidebar_order: 50
44
keywords:
55
[
66
"cli",

docs/concepts/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Concepts & Reference
3-
sidebar_order: 160
3+
sidebar_order: 80
44
description: "Learn the basic concepts of Sentry such as searchable properties and data management settings."
55
---
66

docs/organization/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Organization Settings
3-
sidebar_order: 400
3+
sidebar_order: 20
44
description: "Learn how to configure your organization's Sentry account, including 2FA authentication, user management, and data storage location."
55
---
66

docs/pricing/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Pricing & Billing
3-
sidebar_order: 1
3+
sidebar_order: 40
44
description: "Learn about pricing, managing volume, and the different Sentry plans."
55
---
66

docs/product/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Product Walkthroughs
3-
sidebar_order: 1
3+
sidebar_order: 30
44
description: "Get an overview of how you can use Sentry to not just observe, but debug errors, get to the root of user complaints, and identify performance bottlenecks."
55
---
66

docs/security-legal-pii/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: Security, Legal, & PII
3-
sidebar_order: 1
3+
sidebar_order: 70
44
description: "Learn about Sentry's security and compliance processes and how to scrub sensitive data."
55
---
66

src/docTree.spec.ts

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
import {describe, expect, test} from 'vitest';
22

3-
import {DocNode, getCurrentPlatformOrGuide, nodeForPath} from './docTree';
3+
import {
4+
DocNode,
5+
getCurrentPlatformOrGuide,
6+
getNextNode,
7+
isRootGuidePath,
8+
isRootPlatformPath,
9+
nodeForPath,
10+
} from './docTree';
11+
import {FrontMatter} from './types';
412

513
const createRootNode = (): DocNode => ({
614
children: [],
@@ -11,6 +19,19 @@ const createRootNode = (): DocNode => ({
1119
sourcePath: '',
1220
});
1321

22+
const createNode = (path: string, title: string, frontmatter?: FrontMatter): DocNode => ({
23+
children: [],
24+
frontmatter: {
25+
title,
26+
slug: path,
27+
...frontmatter,
28+
},
29+
missing: false,
30+
path,
31+
slug: path,
32+
sourcePath: 'sourcepath',
33+
});
34+
1435
const nextjsRoot = createRootNode();
1536
nextjsRoot.children = [
1637
{
@@ -119,4 +140,101 @@ describe('docTree', () => {
119140
expect(node?.name).toBe('javascript');
120141
});
121142
});
143+
144+
describe('getNextNode', () => {
145+
const rootNode = createRootNode();
146+
147+
const nodeWithChildren = createNode('a', 'A');
148+
nodeWithChildren.children = [createNode('a1', 'A1'), createNode('a2', 'A2')];
149+
nodeWithChildren.children.forEach(child => {
150+
child.parent = nodeWithChildren;
151+
});
152+
153+
rootNode.children = [nodeWithChildren, createNode('b', 'B'), createNode('c', 'C')];
154+
rootNode.children.forEach(child => {
155+
child.parent = rootNode;
156+
});
157+
158+
test('should return first child for root node', () => {
159+
const nextNode = getNextNode(rootNode);
160+
expect(nextNode?.slug).toBe('a');
161+
});
162+
163+
test('should return first child for node with children', () => {
164+
const nextNode = getNextNode(nodeWithChildren);
165+
expect(nextNode?.slug).toBe('a1');
166+
});
167+
168+
test('should return next sibling', () => {
169+
const nextNode = getNextNode(nodeWithChildren.children[0]);
170+
expect(nextNode?.slug).toBe('a2');
171+
});
172+
173+
test('should return sibling of parent if no siblings available', () => {
174+
const nextNode = getNextNode(nodeWithChildren.children[1]);
175+
expect(nextNode?.slug).toBe('b');
176+
});
177+
178+
test('should return undefined if no children or siblings', () => {
179+
const nextNode = getNextNode(createNode('d', 'D'));
180+
expect(nextNode).toBeUndefined();
181+
});
182+
183+
test('should respect sidebar order for sorting', () => {
184+
const root = createRootNode();
185+
const a = createNode('a', 'A', {sidebar_order: 2} as FrontMatter);
186+
const b = createNode('b', 'B', {sidebar_order: 1} as FrontMatter);
187+
root.children = [a, b];
188+
root.children.forEach(child => {
189+
child.parent = root;
190+
});
191+
192+
const a1 = createNode('a1', 'A1', {sidebar_order: 2} as FrontMatter);
193+
const a2 = createNode('a2', 'A2', {sidebar_order: 1} as FrontMatter);
194+
a.children = [a1, a2];
195+
a.children.forEach(child => {
196+
child.parent = a;
197+
});
198+
199+
expect(getNextNode(a)?.slug).toBe('a2');
200+
expect(getNextNode(b)?.slug).toBe('a');
201+
expect(getNextNode(a1)?.slug).toBeUndefined();
202+
});
203+
204+
test('should not return siblings for root platform or guide paths', () => {
205+
expect(
206+
getNextNode(createNode('platforms/javascript', 'JavaScript'))
207+
).toBeUndefined();
208+
expect(
209+
getNextNode(createNode('platforms/javascript/guides/nextjs', 'Next.js'))
210+
).toBeUndefined();
211+
});
212+
});
213+
214+
describe('isRootPlatformPath', () => {
215+
test('should return true for root platform path', () => {
216+
expect(isRootPlatformPath('platforms/javascript')).toBe(true);
217+
expect(isRootPlatformPath('platforms/python')).toBe(true);
218+
});
219+
220+
test('should return false for non-root platform path', () => {
221+
expect(isRootPlatformPath('platforms/javascript/guides/nextjs')).toBe(false);
222+
expect(isRootPlatformPath('platforms/javascript/troubleshooting')).toBe(false);
223+
});
224+
});
225+
226+
describe('isRootGuidePath', () => {
227+
test('should return true for root guide path', () => {
228+
expect(isRootGuidePath('platforms/javascript/guides/nextjs')).toBe(true);
229+
expect(isRootGuidePath('platforms/python/guides/django')).toBe(true);
230+
});
231+
232+
test('should return false for non-root guide path', () => {
233+
expect(isRootGuidePath('platforms/javascript')).toBe(false);
234+
expect(isRootGuidePath('platforms/javascript/troubleshooting/get-started')).toBe(
235+
false
236+
);
237+
expect(isRootGuidePath('platforms/python/guides/django/installation')).toBe(false);
238+
});
239+
});
122240
});

0 commit comments

Comments
 (0)