From 6f6ad52072393ea2ac910fa22a64be5484fa0596 Mon Sep 17 00:00:00 2001 From: Bruno Mercier Costa <94469565+emrcbrn@users.noreply.github.com> Date: Thu, 15 Oct 2026 15:35:51 +0200 Subject: [PATCH] docs: add common issues to the troubleshooting hub and fill out the area tiles (#1039) * docs: add common issues to the troubleshooting hub and fill out the area tiles Lead the Troubleshooting hub with a table of the issues support sees most often, and give each area tile the sections a reader actually needs, including a new Reverse Proxy tile. Add the case where a teammate signs in and gets their own account to the pending approval page, with sign-in domains as the fix. List the headings rendered by the troubleshooting components in "On this page", which previously only showed Markdown headings. * docs: address review on account-access and support wording - Personal-address teammate: drop the direct-invite advice, since a user who already has an account can't be invited; point to the work address or NetBird Support instead. - Support audience: say NetBird Support is mainly for paying Cloud customers and commercial-license deployments, consistently across the troubleshooting hub, the support page, and the report-bug page. * docs: align the troubleshooting hub table and rework Still stuck - Common issues table: fixed 50/50 columns, with the Start here column padded to line up with the right-hand area tiles at any width. - Still stuck: match the width and side padding of the tiles, center the title and buttons, and put a short audience note under each button. The report hint moves to its own line above the links, with a new Debug bundle link. --- mdx/rehype.mjs | 21 ++- src/components/StillStuck.jsx | 113 ++++++++++---- src/pages/help/netbird-support.mdx | 4 +- src/pages/help/report-bug-issues.mdx | 2 +- .../help/troubleshooting-account-access.mdx | 28 +++- src/pages/help/troubleshooting.mdx | 145 ++++++++++++------ src/pages/selfhosted/troubleshooting.mdx | 1 + 7 files changed, 237 insertions(+), 77 deletions(-) diff --git a/mdx/rehype.mjs b/mdx/rehype.mjs index d6b85d9d..4dfa606c 100644 --- a/mdx/rehype.mjs +++ b/mdx/rehype.mjs @@ -165,11 +165,30 @@ function rehypeAddMDXExports(getExports) { } } +// Components that render their own `h2` from `title` and `id` props. The +// heading is not in the MDX tree, so it is added to the table of contents here. +const sectionComponents = ['TroubleshootingStart', 'TroubleshootingTiles', 'StillStuck'] + +function jsxStringAttribute(node, name) { + let attribute = node.attributes?.find((a) => a.name === name) + return typeof attribute?.value === 'string' ? attribute.value : undefined +} + function getSections(node) { let sections = [] for (let child of node.children ?? []) { - if (child.type === 'element' && ['h2', 'h3', 'h4', 'h5', 'h6'].includes(child.tagName)) { + if (child.type === 'mdxJsxFlowElement' && sectionComponents.includes(child.name)) { + let title = jsxStringAttribute(child, 'title') + let id = jsxStringAttribute(child, 'id') + if (title && id) { + sections.push(`{ + title: ${JSON.stringify(title)}, + id: ${JSON.stringify(id)}, + tagName: "h2" + }`) + } + } else if (child.type === 'element' && ['h2', 'h3', 'h4', 'h5', 'h6'].includes(child.tagName)) { sections.push(`{ title: ${JSON.stringify(toString(child))}, id: ${JSON.stringify(child.properties.id)}, diff --git a/src/components/StillStuck.jsx b/src/components/StillStuck.jsx index 5eb9b145..06920e74 100644 --- a/src/components/StillStuck.jsx +++ b/src/components/StillStuck.jsx @@ -1,48 +1,105 @@ import { Fragment } from 'react' +import Link from 'next/link' import { Button } from '@/components/Button' /** * "Still stuck?" call-to-action banner for the bottom of the Troubleshooting - * hub. Renders a short prompt and a row of action buttons. + * hub. Renders a centered title, a row of action buttons with an optional note + * under each, and an optional row of secondary links. * * @param {string} [title='Still stuck?'] - * @param {string} description - * @param {Array<{label: string, href: string, primary?: boolean}>} actions + * @param {string} [id] - Optional id for the title anchor (listed in "On this page") + * @param {string} [description] + * @param {Array<{label: string, href: string, primary?: boolean, note?: string}>} actions * @param {string} [separator] - Optional word rendered between buttons (e.g. "or"), * so two equally-weighted actions don't read as a recommended-vs-secondary pair. + * @param {string} [linksLabel] - Lead-in text, on its own line above the secondary links + * @param {Array<{label: string, href: string}>} [links] - Secondary text links */ export function StillStuck({ title = 'Still stuck?', + id, description, actions = [], separator, + linksLabel, + links = [], }) { + // `not-prose` on the card would also drop the prose layout (left margin and + // max width), so the outer div keeps it and matches TroubleshootingTiles. return ( -
- {description} -
- )} -+ {description} +
+ )} + {/* Stacked in reading order on phones. From `sm` up, a two-row grid puts + each note under its button and keeps the separator level with the + buttons, not the notes. */} ++ {action.note} +
+ )} +{linksLabel}
} +
+ {links.map((link, i) => (
+