diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx index 3e26b1f62ff..89b64e78b9d 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx @@ -43,9 +43,10 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any const { resolvedTheme } = useTheme() const activeItem = props.subItem.url === pathname const activeItemRef = useRef(null) + const hasChildren = props.subItem.items && props.subItem.items.length > 0 const isChildActive = - props.subItem.items && + hasChildren && props.subItem.items.some((child: NavAccordionItem) => hasActiveDescendant(child, pathname)) const LinkContainer = (props) => { @@ -73,16 +74,8 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any } }) return ( - <> - {props.subItemIndex === 0 && ( - <> -
- - {props.parent.name} - - - )} - {props.subItem.items && props.subItem.items.length > 0 ? ( +
  • + {hasChildren ? ( - {props.subItem.items - .filter((subItem) => subItem.enabled !== false) - .map((subSubItem) => { - if (subSubItem.items && subSubItem.items.length > 0) { - return ( - - ) - } +
      + {props.subItem.items + .filter((subItem) => subItem.enabled !== false) + .map((subSubItem) => { + if (subSubItem.items && subSubItem.items.length > 0) { + return + } - return ( -
    • - - {subSubItem.name} - -
    • - ) - })} + return ( +
    • + + {subSubItem.name} + +
    • + ) + })} +
    ) : ( -
  • - -
    - {props.subItem.icon && ( - {props.subItem.name} - )} - {props.subItem.name} -
    -
    -
  • + +
    + {props.subItem.icon && ( + {props.subItem.name} + )} + {props.subItem.name} +
    +
    )} - + ) }) @@ -210,7 +196,7 @@ const Content = (props) => { } return ( - + + ) } diff --git a/e2e/docs/utils/resolve-docs-scope.test.ts b/e2e/docs/utils/resolve-docs-scope.test.ts new file mode 100644 index 00000000000..15eadef1560 --- /dev/null +++ b/e2e/docs/utils/resolve-docs-scope.test.ts @@ -0,0 +1,31 @@ +import assert from 'node:assert/strict' +import test from 'node:test' +import { fileURLToPath } from 'node:url' + +import { + GUIDE_LIST_COMPONENT, + GUIDE_LIST_COMPONENT_PAGES, + resolveDocsScope, +} from './resolve-docs-scope.ts' + +const repoRoot = fileURLToPath(new URL('../../..', import.meta.url)) + +test('maps a guide list component change to its sample pages', async () => { + const result = await resolveDocsScope({ + changedFiles: [GUIDE_LIST_COMPONENT], + repoRoot, + }) + + assert.deepEqual(result.pages, [...GUIDE_LIST_COMPONENT_PAGES].sort()) + assert.equal(result.skip, false) +}) + +test('ignores unrelated docs component changes', async () => { + const result = await resolveDocsScope({ + changedFiles: ['apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts'], + repoRoot, + }) + + assert.deepEqual(result.pages, []) + assert.equal(result.skip, true) +}) diff --git a/e2e/docs/utils/resolve-docs-scope.ts b/e2e/docs/utils/resolve-docs-scope.ts index 2c5325cbac9..1a5f66ba488 100644 --- a/e2e/docs/utils/resolve-docs-scope.ts +++ b/e2e/docs/utils/resolve-docs-scope.ts @@ -19,6 +19,14 @@ const PARTIALS_PREFIX = 'apps/docs/content/_partials/' const DOCS_GUIDES_URL_PREFIX = '/docs/guides/' const DOCS_TROUBLESHOOTING_URL_PREFIX = '/docs/guides/troubleshooting/' const FEDERATED_CONTENT_SOURCES_DIR = 'apps/docs/scripts/federated-content/sources' +export const GUIDE_LIST_COMPONENT = + 'apps/docs/components/Navigation/NavigationMenu/NavigationMenuGuideListItems.tsx' + +export const GUIDE_LIST_COMPONENT_PAGES = [ + '/docs/guides/getting-started/api-keys', + '/docs/guides/getting-started/quickstarts/nextjs', + '/docs/guides/integrations/build-a-supabase-oauth-integration/oauth-scopes', +] const PARTIAL_PATH_RE = /<\$Partial\b[\s\S]*?\bpath\s*=\s*"([^"]+)"[\s\S]*?\/?>/g const SOURCE_SECTION_RE = /\bsection:\s*'([^']+)'/g @@ -246,9 +254,15 @@ export async function resolveDocsScope( const maxPages = options.maxPages ?? MAX_SCOPED_PAGES const pages = new Set() + const requiredPages = new Set() const changedPartials: string[] = [] for (const file of options.changedFiles) { + if (normalizeRepoPath(file) === GUIDE_LIST_COMPONENT) { + for (const page of GUIDE_LIST_COMPONENT_PAGES) requiredPages.add(page) + continue + } + const page = changedFileToPagePath(file) if (page) { pages.add(page) @@ -271,7 +285,13 @@ export async function resolveDocsScope( } } - const sorted = [...pages].sort().slice(0, maxPages) + const selectedRequiredPages = [...requiredPages].sort().slice(0, maxPages) + const remainingSlots = Math.max(0, maxPages - selectedRequiredPages.length) + const selectedPages = [...pages] + .filter((page) => !requiredPages.has(page)) + .sort() + .slice(0, remainingSlots) + const sorted = [...selectedRequiredPages, ...selectedPages].sort() return { pages: sorted,