diff --git a/app/[[...path]]/page.tsx b/app/[[...path]]/page.tsx
index a3df97f0c781f..63da6193e8860 100644
--- a/app/[[...path]]/page.tsx
+++ b/app/[[...path]]/page.tsx
@@ -11,8 +11,11 @@ import {Home} from 'sentry-docs/components/home';
import {Include} from 'sentry-docs/components/include';
import {PlatformContent} from 'sentry-docs/components/platformContent';
import {
+ DocNode,
getCurrentPlatformOrGuide,
getDocsRootNode,
+ getNextNode,
+ getPreviousNode,
nodeForPath,
} from 'sentry-docs/docTree';
import {isDeveloperDocs} from 'sentry-docs/isDeveloperDocs';
@@ -24,6 +27,7 @@ import {
} from 'sentry-docs/mdx';
import {mdxComponents} from 'sentry-docs/mdxComponents';
import {setServerContext} from 'sentry-docs/serverContext';
+import {PaginationNavNode} from 'sentry-docs/types/paginationNavNode';
import {stripVersion} from 'sentry-docs/versioning';
export async function generateStaticParams() {
@@ -42,7 +46,11 @@ export const dynamic = 'force-static';
const mdxComponentsWithWrapper = mdxComponents(
{Include, PlatformContent},
- ({children, frontMatter}) => {children}
+ ({children, frontMatter, nextPage, previousPage}) => (
+
+ {children}
+
+ )
);
function MDXLayoutRenderer({mdxSource, ...rest}) {
@@ -59,6 +67,42 @@ export default async function Page({params}: {params: {path?: string[]}}) {
path: params.path ?? [],
});
+ if (!params.path && !isDeveloperDocs) {
+ return ;
+ }
+
+ const pageNode = nodeForPath(rootNode, params.path ?? '');
+
+ if (!pageNode) {
+ // eslint-disable-next-line no-console
+ console.warn('no page node', params.path);
+ return notFound();
+ }
+
+ // gather previous and next page that will be displayed in the bottom pagination
+ const getPaginationDetails = (
+ getNode: (node: DocNode) => DocNode | undefined | 'root',
+ page: PaginationNavNode | undefined
+ ) => {
+ if (page && 'path' in page && 'title' in page) {
+ return page;
+ }
+
+ const node = getNode(pageNode);
+
+ if (node === 'root') {
+ return {path: '', title: 'Welcome to Sentry'};
+ }
+
+ return node ? {path: node.path, title: node.frontmatter.title} : undefined;
+ };
+
+ const previousPage = getPaginationDetails(
+ getPreviousNode,
+ pageNode?.frontmatter?.previousPage
+ );
+ const nextPage = getPaginationDetails(getNextNode, pageNode?.frontmatter?.nextPage);
+
if (isDeveloperDocs) {
// get the MDX for the current doc and render it
let doc: Awaited> | null = null;
@@ -74,13 +118,17 @@ export default async function Page({params}: {params: {path?: string[]}}) {
}
const {mdxSource, frontMatter} = doc;
// pass frontmatter tree into sidebar, rendered page + fm into middle, headers into toc
- return ;
- }
- if (!params.path) {
- return ;
+ return (
+
+ );
}
- if (params.path[0] === 'api' && params.path.length > 1) {
+ if (params.path?.[0] === 'api' && params.path.length > 1) {
const categories = await apiCategories();
const category = categories.find(c => c.slug === params?.path?.[1]);
if (category) {
@@ -94,14 +142,6 @@ export default async function Page({params}: {params: {path?: string[]}}) {
}
}
- const pageNode = nodeForPath(rootNode, params.path);
-
- if (!pageNode) {
- // eslint-disable-next-line no-console
- console.warn('no page node', params.path);
- return notFound();
- }
-
// get the MDX for the current doc and render it
let doc: Awaited> | null = null;
try {
@@ -122,7 +162,12 @@ export default async function Page({params}: {params: {path?: string[]}}) {
// pass frontmatter tree into sidebar, rendered page + fm into middle, headers into toc.
return (
-
+
);
}
diff --git a/develop-docs/application/index.mdx b/develop-docs/application/index.mdx
index 49613ad5a6e59..6a71b4d9473c5 100644
--- a/develop-docs/application/index.mdx
+++ b/develop-docs/application/index.mdx
@@ -1,5 +1,6 @@
---
title: Application
+sidebar_order: 30
---
diff --git a/develop-docs/development/environment/index.mdx b/develop-docs/development/environment/index.mdx
index 919eaeeac5fcf..449f77a5afc06 100644
--- a/develop-docs/development/environment/index.mdx
+++ b/develop-docs/development/environment/index.mdx
@@ -1,7 +1,7 @@
---
title: Environment
description: This guide steps you through configuring a local development environment for the Sentry server on macOS and Linux.
-sidebar_order: 1
+sidebar_order: 2
---
If you're using
diff --git a/develop-docs/integrations/index.mdx b/develop-docs/integrations/index.mdx
index 6dc434f2599e2..91fff36c5fb52 100644
--- a/develop-docs/integrations/index.mdx
+++ b/develop-docs/integrations/index.mdx
@@ -1,6 +1,6 @@
---
title: Developing Integrations
-sidebar_order: 80
+sidebar_order: 90
---
diff --git a/develop-docs/relay/index.mdx b/develop-docs/relay/index.mdx
index fddf4b8eaaf05..e5a08ce7a094c 100644
--- a/develop-docs/relay/index.mdx
+++ b/develop-docs/relay/index.mdx
@@ -1,6 +1,6 @@
---
title: Relay Development
-sidebar_order: 60
+sidebar_order: 70
---
Relay is a service for event filtering, rate-limiting and processing. It can act as:
diff --git a/develop-docs/sdk/index.mdx b/develop-docs/sdk/index.mdx
index 348cd7a0fc432..ca0e378a5761d 100644
--- a/develop-docs/sdk/index.mdx
+++ b/develop-docs/sdk/index.mdx
@@ -1,6 +1,6 @@
---
title: SDK Development
-sidebar_order: 70
+sidebar_order: 60
---
The following is a guide for implementing a Sentry SDK.
diff --git a/develop-docs/self-hosted/index.mdx b/develop-docs/self-hosted/index.mdx
index 71cd7db789278..ce425c4ad6b15 100644
--- a/develop-docs/self-hosted/index.mdx
+++ b/develop-docs/self-hosted/index.mdx
@@ -1,6 +1,6 @@
---
title: Self-Hosted Sentry
-sidebar_order: 30
+sidebar_order: 100
---
In addition to making its source code available publicly, Sentry offers and maintains a minimal setup that works out-of-the-box for simple use cases. This version comes with no guarantees or dedicated support. Sentry engineers will do their best to answer questions and are dedicated to making sure self-hosted is running, but that's where our involvement ends. For anything else, we expect users to rely on the [Sentry Self-Hosted community](https://discord.gg/sentry) on Discord. The self-hosted repository should serve as a blueprint for how various Sentry services connect for a complete setup. This will be useful for folks willing to maintain larger installations with custom infrastructure.
diff --git a/develop-docs/self-hosted/releases.mdx b/develop-docs/self-hosted/releases.mdx
index bc2bfc945e62a..3bf93c03adee9 100644
--- a/develop-docs/self-hosted/releases.mdx
+++ b/develop-docs/self-hosted/releases.mdx
@@ -1,7 +1,7 @@
---
title: Self-Hosted Releases & Upgrading
sidebar_title: Releases & Upgrading
-sidebar_order: 10
+sidebar_order: 1
---
Sentry cuts regular releases for self-hosting to keep it as close to [sentry.io](https://sentry.io) as possible. We decided to follow a monthly release schedule using the [CalVer](https://calver.org/#scheme) versioning scheme, with a primary release on the [15th of each month](https://github.com/getsentry/self-hosted/blob/704e4c3b5b7360080f79bcfbe26583e5a95ae675/.github/workflows/release.yml#L20-L24). We don't patch old versions, but if a bug is bad enough we may cut an out-of-cycle point release, which, like our regular monthly releases, is a snapshot of the latest versions of all of our components. You can find the [latest release](https://github.com/getsentry/self-hosted/releases/latest) over at the [releases section of our self-hosted repository](https://github.com/getsentry/self-hosted/releases/).
diff --git a/develop-docs/services/index.mdx b/develop-docs/services/index.mdx
index f2a90bbfe0353..6d86a306fdc12 100644
--- a/develop-docs/services/index.mdx
+++ b/develop-docs/services/index.mdx
@@ -1,6 +1,6 @@
---
title: Services
-sidebar_order: 60
+sidebar_order: 80
---
diff --git a/docs/account/index.mdx b/docs/account/index.mdx
index bbc2812c09621..5a3f45de5441e 100644
--- a/docs/account/index.mdx
+++ b/docs/account/index.mdx
@@ -1,6 +1,6 @@
---
title: Account Settings
-sidebar_order: 400
+sidebar_order: 10
description: "Learn about Sentry's user settings and auth tokens."
---
diff --git a/docs/api/index.mdx b/docs/api/index.mdx
index 1cc66825f444c..99af633b63f04 100644
--- a/docs/api/index.mdx
+++ b/docs/api/index.mdx
@@ -1,5 +1,6 @@
---
title: API Reference
+sidebar_order: 60
---
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.
diff --git a/docs/cli/index.mdx b/docs/cli/index.mdx
index 2fedf46f55688..04ef078fca840 100644
--- a/docs/cli/index.mdx
+++ b/docs/cli/index.mdx
@@ -1,6 +1,6 @@
---
title: "Sentry CLI"
-sidebar_order: 4000
+sidebar_order: 50
keywords:
[
"cli",
diff --git a/docs/concepts/index.mdx b/docs/concepts/index.mdx
index e22c674675faf..98ffacb44ea2c 100644
--- a/docs/concepts/index.mdx
+++ b/docs/concepts/index.mdx
@@ -1,6 +1,6 @@
---
title: Concepts & Reference
-sidebar_order: 160
+sidebar_order: 80
description: "Learn the basic concepts of Sentry such as searchable properties and data management settings."
---
diff --git a/docs/contributing/pages/frontmatter.mdx b/docs/contributing/pages/frontmatter.mdx
index 13713dc44e6d3..ec897f596a558 100644
--- a/docs/contributing/pages/frontmatter.mdx
+++ b/docs/contributing/pages/frontmatter.mdx
@@ -47,3 +47,13 @@ Much of the other functionality for pages is also driven via frontmatter, such a
- [Redirects](../redirects/)
- [Search](../search/)
+
+`nextPage` (`{ path: 'path/to/page', title: 'Page Title' }`)
+
+Overrides the next page shown in the bottom pagination navigation.
+
+`previousPage` (`{ path: 'path/to/page', title: 'Page Title' }`)
+
+Overrides the previous page shown in the bottom pagination navigation.
+
+
diff --git a/docs/organization/index.mdx b/docs/organization/index.mdx
index cff5bb5e22cc3..932d68187ff05 100644
--- a/docs/organization/index.mdx
+++ b/docs/organization/index.mdx
@@ -1,6 +1,6 @@
---
title: Organization Settings
-sidebar_order: 400
+sidebar_order: 20
description: "Learn how to configure your organization's Sentry account, including 2FA authentication, user management, and data storage location."
---
diff --git a/docs/pricing/index.mdx b/docs/pricing/index.mdx
index 0d19628b498b1..c3e297ce23298 100644
--- a/docs/pricing/index.mdx
+++ b/docs/pricing/index.mdx
@@ -1,6 +1,6 @@
---
title: Pricing & Billing
-sidebar_order: 1
+sidebar_order: 40
description: "Learn about pricing, managing volume, and the different Sentry plans."
---
diff --git a/docs/product/index.mdx b/docs/product/index.mdx
index 24bef4bba613a..2ca8fd6b939ae 100644
--- a/docs/product/index.mdx
+++ b/docs/product/index.mdx
@@ -1,6 +1,6 @@
---
title: Product Walkthroughs
-sidebar_order: 1
+sidebar_order: 30
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."
---
diff --git a/docs/security-legal-pii/index.mdx b/docs/security-legal-pii/index.mdx
index 7ae239c400396..7422e82adcdd6 100644
--- a/docs/security-legal-pii/index.mdx
+++ b/docs/security-legal-pii/index.mdx
@@ -1,6 +1,6 @@
---
title: Security, Legal, & PII
-sidebar_order: 1
+sidebar_order: 70
description: "Learn about Sentry's security and compliance processes and how to scrub sensitive data."
---
diff --git a/src/components/docPage/index.tsx b/src/components/docPage/index.tsx
index c6a10390c48c1..5748ea9d5568d 100644
--- a/src/components/docPage/index.tsx
+++ b/src/components/docPage/index.tsx
@@ -3,6 +3,7 @@ import {ReactNode} from 'react';
import {getCurrentGuide, getCurrentPlatform, nodeForPath} from 'sentry-docs/docTree';
import {serverContext} from 'sentry-docs/serverContext';
import {FrontMatter} from 'sentry-docs/types';
+import {PaginationNavNode} from 'sentry-docs/types/paginationNavNode';
import {isTruthy} from 'sentry-docs/utils';
import {getUnversionedPath} from 'sentry-docs/versioning';
@@ -12,6 +13,7 @@ import {Breadcrumbs} from '../breadcrumbs';
import {CodeContextProvider} from '../codeContext';
import {GitHubCTA} from '../githubCTA';
import {Header} from '../header';
+import {PaginationNav} from '../paginationNav';
import {PlatformSdkDetail} from '../platformSdkDetail';
import {Sidebar} from '../sidebar';
import {TableOfContents} from '../tableOfContents';
@@ -21,8 +23,10 @@ type Props = {
frontMatter: Omit;
/** Whether to take all the available width */
fullWidth?: boolean;
+ nextPage?: PaginationNavNode;
/** Whether to hide the table of contents & sdk details */
notoc?: boolean;
+ previousPage?: PaginationNavNode;
sidebar?: ReactNode;
};
@@ -32,6 +36,8 @@ export function DocPage({
notoc = false,
fullWidth = false,
sidebar,
+ nextPage,
+ previousPage,
}: Props) {
const {rootNode, path} = serverContext();
const currentPlatform = getCurrentPlatform(rootNode, path);
@@ -78,6 +84,16 @@ export function DocPage({