From a8454d39af8cd92823611f3e14ef0c58f32b5134 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 23 Oct 2024 11:48:19 +0200 Subject: [PATCH 01/14] feat: add logic for adding next page --- app/[[...path]]/page.tsx | 17 ++++- docs/account/index.mdx | 2 +- docs/api/index.mdx | 1 + docs/cli/index.mdx | 2 +- docs/concepts/index.mdx | 2 +- docs/organization/index.mdx | 2 +- docs/pricing/index.mdx | 2 +- docs/product/index.mdx | 2 +- docs/security-legal-pii/index.mdx | 2 +- src/docTree.spec.ts | 120 +++++++++++++++++++++++++++++- src/docTree.ts | 71 ++++++++++++++++++ 11 files changed, 213 insertions(+), 10 deletions(-) diff --git a/app/[[...path]]/page.tsx b/app/[[...path]]/page.tsx index a3df97f0c781f..47f9425b7f16e 100644 --- a/app/[[...path]]/page.tsx +++ b/app/[[...path]]/page.tsx @@ -13,6 +13,7 @@ import {PlatformContent} from 'sentry-docs/components/platformContent'; import { getCurrentPlatformOrGuide, getDocsRootNode, + getNextNode, nodeForPath, } from 'sentry-docs/docTree'; import {isDeveloperDocs} from 'sentry-docs/isDeveloperDocs'; @@ -42,7 +43,11 @@ export const dynamic = 'force-static'; const mdxComponentsWithWrapper = mdxComponents( {Include, PlatformContent}, - ({children, frontMatter}) => {children} + ({children, frontMatter, nextPage}) => ( + + {children} + + ) ); function MDXLayoutRenderer({mdxSource, ...rest}) { @@ -95,6 +100,10 @@ export default async function Page({params}: {params: {path?: string[]}}) { } const pageNode = nodeForPath(rootNode, params.path); + const nextNode = pageNode ? getNextNode(pageNode) : undefined; + const nextPage = nextNode + ? {path: nextNode.path, title: nextNode.frontmatter.title} + : undefined; if (!pageNode) { // eslint-disable-next-line no-console @@ -122,7 +131,11 @@ 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/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/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/docTree.spec.ts b/src/docTree.spec.ts index bd537f0f71d61..ba166d024b01f 100644 --- a/src/docTree.spec.ts +++ b/src/docTree.spec.ts @@ -1,6 +1,14 @@ import {describe, expect, test} from 'vitest'; -import {DocNode, getCurrentPlatformOrGuide, nodeForPath} from './docTree'; +import { + DocNode, + getCurrentPlatformOrGuide, + getNextNode, + isRootGuidePath, + isRootPlatformPath, + nodeForPath, +} from './docTree'; +import {FrontMatter} from './types'; const createRootNode = (): DocNode => ({ children: [], @@ -11,6 +19,19 @@ const createRootNode = (): DocNode => ({ sourcePath: '', }); +const createNode = (path: string, title: string, frontmatter?: FrontMatter): DocNode => ({ + children: [], + frontmatter: { + title, + slug: path, + ...frontmatter, + }, + missing: false, + path, + slug: path, + sourcePath: 'sourcepath', +}); + const nextjsRoot = createRootNode(); nextjsRoot.children = [ { @@ -119,4 +140,101 @@ describe('docTree', () => { expect(node?.name).toBe('javascript'); }); }); + + describe('getNextNode', () => { + const rootNode = createRootNode(); + + const nodeWithChildren = createNode('a', 'A'); + nodeWithChildren.children = [createNode('a1', 'A1'), createNode('a2', 'A2')]; + nodeWithChildren.children.forEach(child => { + child.parent = nodeWithChildren; + }); + + rootNode.children = [nodeWithChildren, createNode('b', 'B'), createNode('c', 'C')]; + rootNode.children.forEach(child => { + child.parent = rootNode; + }); + + test('should return first child for root node', () => { + const nextNode = getNextNode(rootNode); + expect(nextNode?.slug).toBe('a'); + }); + + test('should return first child for node with children', () => { + const nextNode = getNextNode(nodeWithChildren); + expect(nextNode?.slug).toBe('a1'); + }); + + test('should return next sibling', () => { + const nextNode = getNextNode(nodeWithChildren.children[0]); + expect(nextNode?.slug).toBe('a2'); + }); + + test('should return sibling of parent if no siblings available', () => { + const nextNode = getNextNode(nodeWithChildren.children[1]); + expect(nextNode?.slug).toBe('b'); + }); + + test('should return undefined if no children or siblings', () => { + const nextNode = getNextNode(createNode('d', 'D')); + expect(nextNode).toBeUndefined(); + }); + + test('should respect sidebar order for sorting', () => { + const root = createRootNode(); + const a = createNode('a', 'A', {sidebar_order: 2} as FrontMatter); + const b = createNode('b', 'B', {sidebar_order: 1} as FrontMatter); + root.children = [a, b]; + root.children.forEach(child => { + child.parent = root; + }); + + const a1 = createNode('a1', 'A1', {sidebar_order: 2} as FrontMatter); + const a2 = createNode('a2', 'A2', {sidebar_order: 1} as FrontMatter); + a.children = [a1, a2]; + a.children.forEach(child => { + child.parent = a; + }); + + expect(getNextNode(a)?.slug).toBe('a2'); + expect(getNextNode(b)?.slug).toBe('a'); + expect(getNextNode(a1)?.slug).toBeUndefined(); + }); + + test('should not return siblings for root platform or guide paths', () => { + expect( + getNextNode(createNode('platforms/javascript', 'JavaScript')) + ).toBeUndefined(); + expect( + getNextNode(createNode('platforms/javascript/guides/nextjs', 'Next.js')) + ).toBeUndefined(); + }); + }); + + describe('isRootPlatformPath', () => { + test('should return true for root platform path', () => { + expect(isRootPlatformPath('platforms/javascript')).toBe(true); + expect(isRootPlatformPath('platforms/python')).toBe(true); + }); + + test('should return false for non-root platform path', () => { + expect(isRootPlatformPath('platforms/javascript/guides/nextjs')).toBe(false); + expect(isRootPlatformPath('platforms/javascript/troubleshooting')).toBe(false); + }); + }); + + describe('isRootGuidePath', () => { + test('should return true for root guide path', () => { + expect(isRootGuidePath('platforms/javascript/guides/nextjs')).toBe(true); + expect(isRootGuidePath('platforms/python/guides/django')).toBe(true); + }); + + test('should return false for non-root guide path', () => { + expect(isRootGuidePath('platforms/javascript')).toBe(false); + expect(isRootGuidePath('platforms/javascript/troubleshooting/get-started')).toBe( + false + ); + expect(isRootGuidePath('platforms/python/guides/django/installation')).toBe(false); + }); + }); }); diff --git a/src/docTree.ts b/src/docTree.ts index 008b2205a5044..e14bbb1f27883 100644 --- a/src/docTree.ts +++ b/src/docTree.ts @@ -146,6 +146,65 @@ export function nodeForPath(node: DocNode, path: string | string[]): DocNode | u return node; } +/** + * Returns the next node in the tree, which is either the first child, + * the next sibling, or the next sibling of a parent node. + * + * @param node The current DocNode + * @returns The next DocNode in the tree, or undefined if there is no next node + */ +export const getNextNode = (node: DocNode): DocNode | undefined => { + const children = node.children.filter(filterVisibleSiblings).sort(sortSiblingsByOrder); + // Check for children first + if (children.length > 0) { + return children[0]; + } + + // If no children, look for siblings or parent siblings + let currentNode: DocNode | undefined = node; + while (currentNode?.parent) { + if ( + isRootPlatformPath(currentNode.parent.path) || + isRootGuidePath(currentNode.parent.path) + ) { + return undefined; + } + + const nextSibling = getNextSiblingNode(currentNode); + if (nextSibling) { + return nextSibling; + } + currentNode = currentNode.parent; + } + + // If we've reached this point, there are no more nodes to traverse + return undefined; +}; + +const sortSiblingsByOrder = (a: DocNode, b: DocNode) => + (a.frontmatter.sidebar_order ?? 10) - (b.frontmatter.sidebar_order ?? 10); + +const filterVisibleSiblings = (s: DocNode) => + (s.frontmatter.sidebar_title || s.frontmatter.title) && + !s.frontmatter.sidebar_hidden && + !s.frontmatter.draft && + s.path; + +const getNextSiblingNode = (node: DocNode): DocNode | undefined => { + // filter out root platform and guide paths as these siblings do not make sense in navigation + if (node.parent) { + const siblings = node.parent.children + .sort(sortSiblingsByOrder) + .filter(filterVisibleSiblings); + + const index = siblings.indexOf(node); + if (index < siblings.length - 1) { + return siblings[index + 1]; + } + } + return undefined; +}; + function nodeToPlatform(n: DocNode): Platform { const platformData = platformsData()[n.slug]; const caseStyle = platformData?.case_style || n.frontmatter.caseStyle; @@ -183,6 +242,18 @@ function nodeToGuide(platform: string, n: DocNode): PlatformGuide { }; } +export const isRootPlatformPath = (path: string) => { + return path.startsWith('platforms/') && path.split('/').length === 2; +}; + +export const isRootGuidePath = (path: string) => { + return ( + path.startsWith('platforms/') && + path.split('/').length === 4 && + path.split('/')[2].startsWith('guides') + ); +}; + export function getPlatform(rootNode: DocNode, name: string): Platform | undefined { const platformNode = nodeForPath(rootNode, ['platforms', name]); if (!platformNode) { From 93f0d4496068176e0bf9797c64a833d76149e611 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 23 Oct 2024 12:23:18 +0200 Subject: [PATCH 02/14] feat: add functionality for getting previous page --- app/[[...path]]/page.tsx | 10 +++- src/components/sidebar/sidebarLinks.tsx | 1 + src/docTree.spec.ts | 57 +++++++++++++++++++++++ src/docTree.ts | 61 +++++++++++++++++++------ 4 files changed, 112 insertions(+), 17 deletions(-) diff --git a/app/[[...path]]/page.tsx b/app/[[...path]]/page.tsx index 47f9425b7f16e..834c9f006f248 100644 --- a/app/[[...path]]/page.tsx +++ b/app/[[...path]]/page.tsx @@ -14,6 +14,7 @@ import { getCurrentPlatformOrGuide, getDocsRootNode, getNextNode, + getPreviousNode, nodeForPath, } from 'sentry-docs/docTree'; import {isDeveloperDocs} from 'sentry-docs/isDeveloperDocs'; @@ -43,8 +44,8 @@ export const dynamic = 'force-static'; const mdxComponentsWithWrapper = mdxComponents( {Include, PlatformContent}, - ({children, frontMatter, nextPage}) => ( - + ({children, frontMatter, nextPage, previousPage}) => ( + {children} ) @@ -101,9 +102,13 @@ export default async function Page({params}: {params: {path?: string[]}}) { const pageNode = nodeForPath(rootNode, params.path); const nextNode = pageNode ? getNextNode(pageNode) : undefined; + const previousNode = pageNode ? getPreviousNode(pageNode) : undefined; const nextPage = nextNode ? {path: nextNode.path, title: nextNode.frontmatter.title} : undefined; + const previousPage = previousNode + ? {path: previousNode.path, title: previousNode.frontmatter.title} + : undefined; if (!pageNode) { // eslint-disable-next-line no-console @@ -135,6 +140,7 @@ export default async function Page({params}: {params: {path?: string[]}}) { mdxSource={mdxSource} frontMatter={{...frontMatter, versions}} nextPage={nextPage} + previousPage={previousPage} /> ); } diff --git a/src/components/sidebar/sidebarLinks.tsx b/src/components/sidebar/sidebarLinks.tsx index c069a6f3410ab..8c280e7dd7df8 100644 --- a/src/components/sidebar/sidebarLinks.tsx +++ b/src/components/sidebar/sidebarLinks.tsx @@ -11,6 +11,7 @@ import {NavNode} from './types'; import {docNodeToNavNode, getNavNodes} from './utils'; /** a root of `"some-root"` maps to the `/some-root/` url */ +// we should probably get rid of this const productSidebarItems = [ { title: 'Account Settings', diff --git a/src/docTree.spec.ts b/src/docTree.spec.ts index ba166d024b01f..4eb12ecfdb8f5 100644 --- a/src/docTree.spec.ts +++ b/src/docTree.spec.ts @@ -4,6 +4,7 @@ import { DocNode, getCurrentPlatformOrGuide, getNextNode, + getPreviousNode, isRootGuidePath, isRootPlatformPath, nodeForPath, @@ -211,6 +212,62 @@ describe('docTree', () => { }); }); + describe('getPreviousNode', () => { + const root = createRootNode(); + + const a = createNode('a', 'A'); + const a1 = createNode('a1', 'A1'); + const a2 = createNode('a2', 'A2'); + a.children = [a1, a2]; + a.children.forEach(child => { + child.parent = a; + }); + + const b = createNode('b', 'B'); + const c = createNode('c', 'C'); + root.children = [a, b, c]; + root.children.forEach(child => { + child.parent = root; + }); + + test('should return previous child of parent', () => { + expect(getPreviousNode(c)).toBe(b); + }); + + test('should return previous sibling if previous sibling has children', () => { + expect(getPreviousNode(b)).toBe(a); + }); + + test('should return undefined if no children or siblings', () => { + expect(getPreviousNode(createNode('d', 'D'))).toBeUndefined(); + }); + + test('should return parent for first child', () => { + expect(getPreviousNode(a1)).toBe(a); + }); + + test('should respect sidebar order for sorting', () => { + const xRoot = createRootNode(); + const xA = createNode('a', 'A', {sidebar_order: 2} as FrontMatter); + const xB = createNode('b', 'B', {sidebar_order: 1} as FrontMatter); + xRoot.children = [xA, xB]; + xRoot.children.forEach(child => { + child.parent = xRoot; + }); + + expect(getPreviousNode(xA)).toBe(xB); + }); + + test('should not return siblings for root platform or guide paths', () => { + expect( + getPreviousNode(createNode('platforms/javascript', 'JavaScript')) + ).toBeUndefined(); + expect( + getPreviousNode(createNode('platforms/javascript/guides/nextjs', 'Next.js')) + ).toBeUndefined(); + }); + }); + describe('isRootPlatformPath', () => { test('should return true for root platform path', () => { expect(isRootPlatformPath('platforms/javascript')).toBe(true); diff --git a/src/docTree.ts b/src/docTree.ts index e14bbb1f27883..b2d495c3e31d0 100644 --- a/src/docTree.ts +++ b/src/docTree.ts @@ -181,6 +181,52 @@ export const getNextNode = (node: DocNode): DocNode | undefined => { return undefined; }; +/** + * Returns the previous node in the tree, which is either the last child of the parent, + * the previous sibling, or the previous sibling of a parent node. + */ +export const getPreviousNode = (node: DocNode): DocNode | undefined => { + const previousSibling = getPreviousSiblingNode(node); + if (previousSibling) { + return previousSibling; + } + return node.parent; +}; + +const getNextSiblingNode = (node: DocNode): DocNode | undefined => { + if (!node.parent) { + return undefined; + } + + const siblings = node.parent.children + .sort(sortSiblingsByOrder) + .filter(filterVisibleSiblings); + + const index = siblings.indexOf(node); + if (index < siblings.length - 1) { + return siblings[index + 1]; + } + + return undefined; +}; + +const getPreviousSiblingNode = (node: DocNode): DocNode | undefined => { + if (!node.parent) { + return undefined; + } + + const siblings = node.parent.children + .sort(sortSiblingsByOrder) + .filter(filterVisibleSiblings); + + const index = siblings.indexOf(node); + if (index > 0) { + return siblings[index - 1]; + } + + return undefined; +}; + const sortSiblingsByOrder = (a: DocNode, b: DocNode) => (a.frontmatter.sidebar_order ?? 10) - (b.frontmatter.sidebar_order ?? 10); @@ -190,21 +236,6 @@ const filterVisibleSiblings = (s: DocNode) => !s.frontmatter.draft && s.path; -const getNextSiblingNode = (node: DocNode): DocNode | undefined => { - // filter out root platform and guide paths as these siblings do not make sense in navigation - if (node.parent) { - const siblings = node.parent.children - .sort(sortSiblingsByOrder) - .filter(filterVisibleSiblings); - - const index = siblings.indexOf(node); - if (index < siblings.length - 1) { - return siblings[index + 1]; - } - } - return undefined; -}; - function nodeToPlatform(n: DocNode): Platform { const platformData = platformsData()[n.slug]; const caseStyle = platformData?.case_style || n.frontmatter.caseStyle; From dd1026548718dd64f3ce1bd5399966e756806800 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 23 Oct 2024 14:50:53 +0200 Subject: [PATCH 03/14] some fixes for path traversal --- src/docTree.spec.ts | 61 ++++++++++++++++++++++++++++++++++++--------- src/docTree.ts | 23 +++++++++++------ 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/src/docTree.spec.ts b/src/docTree.spec.ts index 4eb12ecfdb8f5..42aae6ae90a36 100644 --- a/src/docTree.spec.ts +++ b/src/docTree.spec.ts @@ -203,12 +203,24 @@ describe('docTree', () => { }); test('should not return siblings for root platform or guide paths', () => { - expect( - getNextNode(createNode('platforms/javascript', 'JavaScript')) - ).toBeUndefined(); - expect( - getNextNode(createNode('platforms/javascript/guides/nextjs', 'Next.js')) - ).toBeUndefined(); + const platforms = createNode('platforms', 'Platforms'); + const js = createNode('platforms/javascript', 'JavaScript'); + const python = createNode('platforms/python', 'Python'); + platforms.children = [js, python]; + platforms.children.forEach(child => { + child.parent = platforms; + }); + + const nextjs = createNode('platforms/javascript/guides/nextjs', 'Next.js'); + const angular = createNode('platforms/javascript/guides/angular', 'Angular'); + js.children = [nextjs, angular]; + js.children.forEach(child => { + child.parent = js; + }); + + expect(getNextNode(js)).toBeUndefined(); + expect(getNextNode(nextjs)).toBeUndefined(); + expect(getNextNode(angular)).toBeUndefined(); }); }); @@ -259,12 +271,37 @@ describe('docTree', () => { }); test('should not return siblings for root platform or guide paths', () => { - expect( - getPreviousNode(createNode('platforms/javascript', 'JavaScript')) - ).toBeUndefined(); - expect( - getPreviousNode(createNode('platforms/javascript/guides/nextjs', 'Next.js')) - ).toBeUndefined(); + const platforms = createNode('platforms', 'Platforms'); + const js = createNode('platforms/javascript', 'JavaScript'); + const python = createNode('platforms/python', 'Python'); + platforms.children = [js, python]; + platforms.children.forEach(child => { + child.parent = platforms; + }); + + const nextjs = createNode('platforms/javascript/guides/nextjs', 'Next.js'); + const angular = createNode('platforms/javascript/guides/angular', 'Angular'); + js.children = [nextjs, angular]; + js.children.forEach(child => { + child.parent = js; + }); + + expect(getPreviousNode(js)).toBe(undefined); + expect(getPreviousNode(python)).toBe(undefined); + expect(getPreviousNode(nextjs)).toBe(undefined); + expect(getPreviousNode(angular)).toBe(undefined); + }); + + test('should not return /platforms as previous page', () => { + const docs = createNode('', 'Docs'); + const platforms = createNode('platforms', 'Platforms'); + const accounts = createNode('accounts', 'Accounts'); + docs.children = [platforms, accounts]; + docs.children.forEach(child => { + child.parent = docs; + }); + + expect(getPreviousNode(accounts)).toBe(undefined); }); }); diff --git a/src/docTree.ts b/src/docTree.ts index b2d495c3e31d0..0adeaeb8d7352 100644 --- a/src/docTree.ts +++ b/src/docTree.ts @@ -156,22 +156,22 @@ export function nodeForPath(node: DocNode, path: string | string[]): DocNode | u export const getNextNode = (node: DocNode): DocNode | undefined => { const children = node.children.filter(filterVisibleSiblings).sort(sortSiblingsByOrder); // Check for children first - if (children.length > 0) { + if ( + children.length > 0 && + !isRootPlatformPath(children[0].path) && + !isRootGuidePath(children[0].path) + ) { return children[0]; } // If no children, look for siblings or parent siblings let currentNode: DocNode | undefined = node; while (currentNode?.parent) { - if ( - isRootPlatformPath(currentNode.parent.path) || - isRootGuidePath(currentNode.parent.path) - ) { - return undefined; - } - const nextSibling = getNextSiblingNode(currentNode); if (nextSibling) { + if (isRootPlatformPath(nextSibling.path) || isRootGuidePath(nextSibling.path)) { + return undefined; + } return nextSibling; } currentNode = currentNode.parent; @@ -186,8 +186,15 @@ export const getNextNode = (node: DocNode): DocNode | undefined => { * the previous sibling, or the previous sibling of a parent node. */ export const getPreviousNode = (node: DocNode): DocNode | undefined => { + if (isRootPlatformPath(node.path) || isRootGuidePath(node.path)) { + return undefined; + } + const previousSibling = getPreviousSiblingNode(node); if (previousSibling) { + if (previousSibling.path === 'platforms') { + return undefined; + } return previousSibling; } return node.parent; From 6f73a581fb41e22c2fd954e5acbdc11d695b138a Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 23 Oct 2024 14:51:15 +0200 Subject: [PATCH 04/14] add ui elements --- src/components/docPage/index.tsx | 16 +++++++++ src/components/githubCTA/styles.module.css | 2 +- src/components/paginationNav.tsx | 42 ++++++++++++++++++++++ src/types/paginationNavNode.ts | 4 +++ 4 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 src/components/paginationNav.tsx create mode 100644 src/types/paginationNavNode.ts diff --git a/src/components/docPage/index.tsx b/src/components/docPage/index.tsx index c6a10390c48c1..6de2c54e8011c 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({
{children}
+ +
+
+ {previousPage && } +
+
+ {nextPage && } +
+
+ {hasGithub && } diff --git a/src/components/githubCTA/styles.module.css b/src/components/githubCTA/styles.module.css index ecf750f7a9b8b..fd3b448f9ccdf 100644 --- a/src/components/githubCTA/styles.module.css +++ b/src/components/githubCTA/styles.module.css @@ -1,6 +1,6 @@ .cta { background: var(--accent-a2); - margin-top: 4rem; + margin-top: 2rem; margin-bottom: 2rem; padding: 1rem 1.25rem; border-radius: 0.25em; diff --git a/src/components/paginationNav.tsx b/src/components/paginationNav.tsx new file mode 100644 index 0000000000000..989a021076a93 --- /dev/null +++ b/src/components/paginationNav.tsx @@ -0,0 +1,42 @@ +import {DoubleArrowLeftIcon, DoubleArrowRightIcon} from '@radix-ui/react-icons'; + +import {PaginationNavNode} from 'sentry-docs/types/paginationNavNode'; + +export function PaginationNav({ + node, + title, +}: { + node: PaginationNavNode; + title: 'Previous' | 'Next'; +}) { + return ( + +
+
{title}
+
+ {title === 'Previous' && ( +
+ +
+ )} + + {node.title} + + {title === 'Next' && ( +
+ +
+ )} +
+
+
+ ); +} diff --git a/src/types/paginationNavNode.ts b/src/types/paginationNavNode.ts new file mode 100644 index 0000000000000..5cfde0ff52a78 --- /dev/null +++ b/src/types/paginationNavNode.ts @@ -0,0 +1,4 @@ +export type PaginationNavNode = { + path: string; + title: string; +}; From cd95fbd5c38111278f1c2b931c816aa1ff7b63f9 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 23 Oct 2024 15:45:08 +0200 Subject: [PATCH 05/14] show welcome page as previous page for root pages --- src/docTree.spec.ts | 10 +++++----- src/docTree.ts | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/docTree.spec.ts b/src/docTree.spec.ts index 42aae6ae90a36..d53d1eba13b92 100644 --- a/src/docTree.spec.ts +++ b/src/docTree.spec.ts @@ -270,7 +270,7 @@ describe('docTree', () => { expect(getPreviousNode(xA)).toBe(xB); }); - test('should not return siblings for root platform or guide paths', () => { + test('should return root as previous page for root platform or guide paths', () => { const platforms = createNode('platforms', 'Platforms'); const js = createNode('platforms/javascript', 'JavaScript'); const python = createNode('platforms/python', 'Python'); @@ -286,10 +286,10 @@ describe('docTree', () => { child.parent = js; }); - expect(getPreviousNode(js)).toBe(undefined); - expect(getPreviousNode(python)).toBe(undefined); - expect(getPreviousNode(nextjs)).toBe(undefined); - expect(getPreviousNode(angular)).toBe(undefined); + expect(getPreviousNode(js)).toBe('root'); + expect(getPreviousNode(python)).toBe('root'); + expect(getPreviousNode(nextjs)).toBe('root'); + expect(getPreviousNode(angular)).toBe('root'); }); test('should not return /platforms as previous page', () => { diff --git a/src/docTree.ts b/src/docTree.ts index 0adeaeb8d7352..0724d861b7c22 100644 --- a/src/docTree.ts +++ b/src/docTree.ts @@ -185,9 +185,10 @@ export const getNextNode = (node: DocNode): DocNode | undefined => { * Returns the previous node in the tree, which is either the last child of the parent, * the previous sibling, or the previous sibling of a parent node. */ -export const getPreviousNode = (node: DocNode): DocNode | undefined => { +export const getPreviousNode = (node: DocNode): DocNode | undefined | 'root' => { + // in this special case, calculating the root node is unnecessary so we return a string instead if (isRootPlatformPath(node.path) || isRootGuidePath(node.path)) { - return undefined; + return 'root'; } const previousSibling = getPreviousSiblingNode(node); From 83b20297fa6ff2036f32e497ec3bc008d6c78f04 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 23 Oct 2024 15:46:55 +0200 Subject: [PATCH 06/14] allow overriding pagination through frontmatter --- app/[[...path]]/page.tsx | 29 +++++++++++++++++++++-------- src/types/frontmatter.ts | 17 ++++++++++++++++- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/app/[[...path]]/page.tsx b/app/[[...path]]/page.tsx index 834c9f006f248..dbd9e53d3dc68 100644 --- a/app/[[...path]]/page.tsx +++ b/app/[[...path]]/page.tsx @@ -101,14 +101,6 @@ export default async function Page({params}: {params: {path?: string[]}}) { } const pageNode = nodeForPath(rootNode, params.path); - const nextNode = pageNode ? getNextNode(pageNode) : undefined; - const previousNode = pageNode ? getPreviousNode(pageNode) : undefined; - const nextPage = nextNode - ? {path: nextNode.path, title: nextNode.frontmatter.title} - : undefined; - const previousPage = previousNode - ? {path: previousNode.path, title: previousNode.frontmatter.title} - : undefined; if (!pageNode) { // eslint-disable-next-line no-console @@ -116,6 +108,27 @@ export default async function Page({params}: {params: {path?: string[]}}) { return notFound(); } + // gather previous and next page that will be displayed in the bottom pagination + let previousPage = pageNode?.frontmatter?.previousPage; + let nextPage = pageNode?.frontmatter?.nextPage; + + if (!nextPage || !('path' in nextPage) || !('title' in nextPage)) { + const nextNode = pageNode ? getNextNode(pageNode) : undefined; + nextPage = nextNode + ? {path: nextNode.path, title: nextNode.frontmatter.title} + : undefined; + } + + if (!previousPage || !('path' in previousPage) || !('title' in previousPage)) { + const previousNode = pageNode ? getPreviousNode(pageNode) : undefined; + previousPage = + previousNode === 'root' + ? {path: '', title: 'Welcome to Sentry'} + : previousNode + ? {path: previousNode.path, title: previousNode.frontmatter.title} + : undefined; + } + // get the MDX for the current doc and render it let doc: Awaited> | null = null; try { diff --git a/src/types/frontmatter.ts b/src/types/frontmatter.ts index 708b1cbd20997..ce50c8efc5239 100644 --- a/src/types/frontmatter.ts +++ b/src/types/frontmatter.ts @@ -1,3 +1,5 @@ +import {PaginationNavNode} from './paginationNavNode'; + /** ** a YAML-formatted blob defined at the top of every markdown or mdx file */ @@ -23,6 +25,11 @@ export interface FrontMatter { * A list of keywords for indexing with search. */ keywords?: string[]; + + /** + * The next page in the bottom pagination navigation. + */ + nextPage?: PaginationNavNode; /** * Set this to true to disable indexing (robots, algolia) of this content. */ @@ -31,11 +38,20 @@ export interface FrontMatter { * Specific guides that this page is not relevant to. */ notSupported?: string[]; + /** * Set this to true to disable page-level table of contents rendering. */ notoc?: boolean; + /** + * The previous page in the bottom pagination navigation. + */ + previousPage?: PaginationNavNode; + + /** + * The next page in the sidebar navigation. + */ /** * Set this to true to hide from the sidebar */ @@ -60,7 +76,6 @@ export interface FrontMatter { * Specific guides that this page is relevant to. */ supported?: string[]; - /** * Available versions for this page * @example ['v7.119.0', 'next'] From fbd12a4a766e4ac570ae752d0bf72c0c3f25edb5 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Wed, 23 Oct 2024 16:25:26 +0200 Subject: [PATCH 07/14] enable this stuff on dev docs --- app/[[...path]]/page.tsx | 74 ++++++++++--------- develop-docs/application/index.mdx | 1 + .../development/environment/index.mdx | 2 +- develop-docs/integrations/index.mdx | 2 +- develop-docs/relay/index.mdx | 2 +- develop-docs/sdk/index.mdx | 2 +- develop-docs/self-hosted/index.mdx | 2 +- develop-docs/self-hosted/releases.mdx | 2 +- develop-docs/services/index.mdx | 2 +- src/docTree.spec.ts | 15 +++- src/docTree.ts | 4 + 11 files changed, 67 insertions(+), 41 deletions(-) diff --git a/app/[[...path]]/page.tsx b/app/[[...path]]/page.tsx index dbd9e53d3dc68..780038e76fbbb 100644 --- a/app/[[...path]]/page.tsx +++ b/app/[[...path]]/page.tsx @@ -65,42 +65,11 @@ export default async function Page({params}: {params: {path?: string[]}}) { path: params.path ?? [], }); - if (isDeveloperDocs) { - // get the MDX for the current doc and render it - let doc: Awaited> | null = null; - try { - doc = await getFileBySlug(`develop-docs/${params.path?.join('/') ?? ''}`); - } catch (e) { - if (e.code === 'ENOENT') { - // eslint-disable-next-line no-console - console.error('ENOENT', params.path); - return notFound(); - } - throw e; - } - const {mdxSource, frontMatter} = doc; - // pass frontmatter tree into sidebar, rendered page + fm into middle, headers into toc - return ; - } - if (!params.path) { + if (!params.path && !isDeveloperDocs) { return ; } - 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) { - if (params.path.length === 2) { - return ; - } - const api = category.apis.find(a => a.slug === params.path?.[2]); - if (api) { - return ; - } - } - } - - const pageNode = nodeForPath(rootNode, params.path); + const pageNode = nodeForPath(rootNode, params.path ?? ''); if (!pageNode) { // eslint-disable-next-line no-console @@ -129,6 +98,45 @@ export default async function Page({params}: {params: {path?: string[]}}) { : undefined; } + if (isDeveloperDocs) { + // get the MDX for the current doc and render it + let doc: Awaited> | null = null; + try { + doc = await getFileBySlug(`develop-docs/${params.path?.join('/') ?? ''}`); + } catch (e) { + if (e.code === 'ENOENT') { + // eslint-disable-next-line no-console + console.error('ENOENT', params.path); + return notFound(); + } + throw e; + } + const {mdxSource, frontMatter} = doc; + // pass frontmatter tree into sidebar, rendered page + fm into middle, headers into toc + return ( + + ); + } + + 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) { + if (params.path.length === 2) { + return ; + } + const api = category.apis.find(a => a.slug === params.path?.[2]); + if (api) { + return ; + } + } + } + // get the MDX for the current doc and render it let doc: Awaited> | null = null; try { 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/src/docTree.spec.ts b/src/docTree.spec.ts index d53d1eba13b92..474e116e5dcbf 100644 --- a/src/docTree.spec.ts +++ b/src/docTree.spec.ts @@ -1,4 +1,4 @@ -import {describe, expect, test} from 'vitest'; +import {describe, expect, test, vi} from 'vitest'; import { DocNode, @@ -303,6 +303,19 @@ describe('docTree', () => { expect(getPreviousNode(accounts)).toBe(undefined); }); + + test('should return undefined for getting-started page in developer docs', () => { + vi.mock('./isDeveloperDocs', () => ({ + isDeveloperDocs: true, + })); + + const home = createNode('', 'Home'); + const gettingStarted = createNode('getting-started', 'Getting Started'); + home.children = [gettingStarted]; + gettingStarted.parent = home; + + expect(getPreviousNode(gettingStarted)).toBeUndefined(); + }); }); describe('isRootPlatformPath', () => { diff --git a/src/docTree.ts b/src/docTree.ts index 0724d861b7c22..6fc2866ce8a11 100644 --- a/src/docTree.ts +++ b/src/docTree.ts @@ -191,6 +191,10 @@ export const getPreviousNode = (node: DocNode): DocNode | undefined | 'root' => return 'root'; } + if (node.path === 'getting-started' && isDeveloperDocs) { + return undefined; + } + const previousSibling = getPreviousSiblingNode(node); if (previousSibling) { if (previousSibling.path === 'platforms') { From 38541284b971397a368302ba8213f2e978eb7d70 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Thu, 24 Oct 2024 10:47:29 +0200 Subject: [PATCH 08/14] increase top margin for pagination --- src/components/docPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/docPage/index.tsx b/src/components/docPage/index.tsx index 6de2c54e8011c..5748ea9d5568d 100644 --- a/src/components/docPage/index.tsx +++ b/src/components/docPage/index.tsx @@ -85,7 +85,7 @@ export function DocPage({ {children} -
+
{previousPage && }
From 6582c1dcad25f0c769059134887135bdb7e046b9 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Mon, 28 Oct 2024 13:25:38 +0100 Subject: [PATCH 09/14] refactor ternaries --- app/[[...path]]/page.tsx | 41 ++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/app/[[...path]]/page.tsx b/app/[[...path]]/page.tsx index 780038e76fbbb..63da6193e8860 100644 --- a/app/[[...path]]/page.tsx +++ b/app/[[...path]]/page.tsx @@ -11,6 +11,7 @@ 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, @@ -26,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() { @@ -78,25 +80,28 @@ export default async function Page({params}: {params: {path?: string[]}}) { } // gather previous and next page that will be displayed in the bottom pagination - let previousPage = pageNode?.frontmatter?.previousPage; - let nextPage = pageNode?.frontmatter?.nextPage; - - if (!nextPage || !('path' in nextPage) || !('title' in nextPage)) { - const nextNode = pageNode ? getNextNode(pageNode) : undefined; - nextPage = nextNode - ? {path: nextNode.path, title: nextNode.frontmatter.title} - : undefined; - } + const getPaginationDetails = ( + getNode: (node: DocNode) => DocNode | undefined | 'root', + page: PaginationNavNode | undefined + ) => { + if (page && 'path' in page && 'title' in page) { + return page; + } - if (!previousPage || !('path' in previousPage) || !('title' in previousPage)) { - const previousNode = pageNode ? getPreviousNode(pageNode) : undefined; - previousPage = - previousNode === 'root' - ? {path: '', title: 'Welcome to Sentry'} - : previousNode - ? {path: previousNode.path, title: previousNode.frontmatter.title} - : undefined; - } + 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 From 8aab1f78b1420e9e5e9bc7ea9d75a7dddb3c2779 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Mon, 28 Oct 2024 13:27:14 +0100 Subject: [PATCH 10/14] remove transitions --- src/components/paginationNav.tsx | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/components/paginationNav.tsx b/src/components/paginationNav.tsx index 989a021076a93..2a44320742d71 100644 --- a/src/components/paginationNav.tsx +++ b/src/components/paginationNav.tsx @@ -10,7 +10,7 @@ export function PaginationNav({ title: 'Previous' | 'Next'; }) { return ( - +
- {title === 'Previous' && ( -
- -
- )} + {title === 'Previous' && } {node.title} - {title === 'Next' && ( -
- -
- )} + {title === 'Next' && }
From ccec99976d5ca51dcb6677b1ece91e49e7de6101 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Mon, 28 Oct 2024 13:30:00 +0100 Subject: [PATCH 11/14] rename sorting func --- src/docTree.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/docTree.ts b/src/docTree.ts index 6fc2866ce8a11..d568f30a6556e 100644 --- a/src/docTree.ts +++ b/src/docTree.ts @@ -154,7 +154,7 @@ export function nodeForPath(node: DocNode, path: string | string[]): DocNode | u * @returns The next DocNode in the tree, or undefined if there is no next node */ export const getNextNode = (node: DocNode): DocNode | undefined => { - const children = node.children.filter(filterVisibleSiblings).sort(sortSiblingsByOrder); + const children = node.children.filter(filterVisibleSiblings).sort(sortBySidebarOrder); // Check for children first if ( children.length > 0 && @@ -211,7 +211,7 @@ const getNextSiblingNode = (node: DocNode): DocNode | undefined => { } const siblings = node.parent.children - .sort(sortSiblingsByOrder) + .sort(sortBySidebarOrder) .filter(filterVisibleSiblings); const index = siblings.indexOf(node); @@ -228,7 +228,7 @@ const getPreviousSiblingNode = (node: DocNode): DocNode | undefined => { } const siblings = node.parent.children - .sort(sortSiblingsByOrder) + .sort(sortBySidebarOrder) .filter(filterVisibleSiblings); const index = siblings.indexOf(node); @@ -239,7 +239,7 @@ const getPreviousSiblingNode = (node: DocNode): DocNode | undefined => { return undefined; }; -const sortSiblingsByOrder = (a: DocNode, b: DocNode) => +const sortBySidebarOrder = (a: DocNode, b: DocNode) => (a.frontmatter.sidebar_order ?? 10) - (b.frontmatter.sidebar_order ?? 10); const filterVisibleSiblings = (s: DocNode) => From 8a448455acd594fff7a9c486f2e07e545f78db29 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Mon, 28 Oct 2024 13:30:30 +0100 Subject: [PATCH 12/14] Update src/components/sidebar/sidebarLinks.tsx Co-authored-by: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> --- src/components/sidebar/sidebarLinks.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/sidebar/sidebarLinks.tsx b/src/components/sidebar/sidebarLinks.tsx index 8c280e7dd7df8..c510d2046fc79 100644 --- a/src/components/sidebar/sidebarLinks.tsx +++ b/src/components/sidebar/sidebarLinks.tsx @@ -11,7 +11,7 @@ import {NavNode} from './types'; import {docNodeToNavNode, getNavNodes} from './utils'; /** a root of `"some-root"` maps to the `/some-root/` url */ -// we should probably get rid of this +// todo: we should probably get rid of this const productSidebarItems = [ { title: 'Account Settings', From 23e06222745acdf50276ff47fe8c214f1fe07e96 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Tue, 29 Oct 2024 12:48:03 +0100 Subject: [PATCH 13/14] update border color on dark mode --- src/components/paginationNav.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/paginationNav.tsx b/src/components/paginationNav.tsx index 2a44320742d71..5b24f516460d4 100644 --- a/src/components/paginationNav.tsx +++ b/src/components/paginationNav.tsx @@ -12,7 +12,7 @@ export function PaginationNav({ return (
From 0e1c2cd3e46c6adacf71ce9f27b290ffb62a03ef Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Tue, 29 Oct 2024 13:01:25 +0100 Subject: [PATCH 14/14] add frontmatter documentation --- docs/contributing/pages/frontmatter.mdx | 10 ++++++++++ 1 file changed, 10 insertions(+) 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. + +