From e8dde2f7eb008a217dcaccf6f03b243d2814e793 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Wed, 9 Aug 2023 16:31:53 -0400 Subject: [PATCH] Compute productGroups children hrefs on server (#40232) --- components/context/MainContext.tsx | 3 -- lib/all-products.js | 3 +- lib/get-product-groups.js | 53 +++++++++++++------ .../components/ProductSelectionCard.tsx | 28 +--------- 4 files changed, 40 insertions(+), 47 deletions(-) diff --git a/components/context/MainContext.tsx b/components/context/MainContext.tsx index 6032466072..fbea6beec2 100644 --- a/components/context/MainContext.tsx +++ b/components/context/MainContext.tsx @@ -9,7 +9,6 @@ export type ProductT = { href: string id: string name: string - versions?: Array } type VersionItem = { @@ -70,7 +69,6 @@ export type MainContextT = { currentProduct?: ProductT currentLayoutName: string isHomepageVersion: boolean - isFPT: boolean data: DataT error: string currentCategory?: string @@ -132,7 +130,6 @@ export const getMainContext = async (req: any, res: any): Promise currentProduct: req.context.productMap[req.context.currentProduct] || null, currentLayoutName: req.context.currentLayoutName, isHomepageVersion: req.context.page?.documentType === 'homepage', - isFPT: req.context.currentVersion === 'free-pro-team@latest', error: req.context.error ? req.context.error.toString() : '', data: { ui: req.context.site.data.ui, diff --git a/lib/all-products.js b/lib/all-products.js index e44c76e35e..a11cfb6c96 100644 --- a/lib/all-products.js +++ b/lib/all-products.js @@ -38,9 +38,8 @@ for (const productId of productIds) { toc, wip: data.wip || false, hidden: data.hidden || false, + versions: applicableVersions, } - - internalProducts[productId].versions = applicableVersions } export const productMap = Object.assign({}, internalProducts, externalProducts) diff --git a/lib/get-product-groups.js b/lib/get-product-groups.js index d2c2cdcf4d..f292230112 100644 --- a/lib/get-product-groups.js +++ b/lib/get-product-groups.js @@ -3,27 +3,53 @@ import path from 'path' import { productMap, data } from './all-products.js' import { renderContentWithFallback } from './render-with-fallback.js' import removeFPTFromPath from './remove-fpt-from-path.js' -import getApplicableVersions from './get-applicable-versions.js' async function getPage(id, lang, pageMap, context) { const productId = id.split('/')[0] const product = productMap[productId] const external = product.external || false // undefined becomes false - // Adding external links to a product group here due to accessibility design changes - // where we removed the sidebar on the homepage - docs-team 2965 - const href = external - ? product.href - : removeFPTFromPath(path.posix.join('/', lang, product.versions[0], id)) + + // The href depends. Initially all we have is an `id` which might be + // something like 'code-security/dependabot'. + // To get from that to a Page instance, we have to "guess" what the + // href might be. + // If URL currently is `/fr/enterprise-server@3.9`, + // we're going to try `/fr/enterprise-server@3.9/code-security/dependabot` + // first. And if the URL is `/en` we'll try `/en/code-security/dependabot`. + // But some pages are not available in all versions. + // So we have to try `product.versions[0]` which comes from the `productMap` + // (not be confused with the `pageMap`!) + // Once we have a page, we can get to its `.applicableVersions`. + // This way, we get the best of both worlds. We use the `currentVersion` + // if it's applicable, but we fall back to the first version if it's not. + let href = product.href + let name = product.name - let versions = getApplicableVersions('*') if (!external) { + // First we have to find it as a page object based on its ID. + href = removeFPTFromPath(path.posix.join('/', lang, context.currentVersion, id)) + if (!pageMap[href]) { + // If the page is not available in the *current* version, we + // fall back it its default version, which is `product.versions[0]`. + // For example, you're on `/en/enterprise-server@3.1` and you're + // but a `/foo/bar` is only available in `enterprise-cloud@latest`. + href = removeFPTFromPath(path.posix.join('/', lang, product.versions[0], id)) + } const page = pageMap[href] if (!page) { throw new Error( - `Unable to find a page by the href '${href}'. Review your 'childGroups' frontmatter maybe.`, + `Unable to find a page by the href '${href}'. Review your 'childGroups' front matter.`, ) } + + // Some should not be included for the current version, and returning + // undefined here means this entry will be filtered out by the caller. + const isFPT = context.currentVersion === 'free-pro-team@latest' + if (!isFPT && !page.applicableVersions.includes(context.currentVersion)) { + return + } + if (page.rawShortTitle) { name = await renderContentWithFallback(page, 'rawShortTitle', context, { textOnly: true, @@ -37,16 +63,13 @@ async function getPage(id, lang, pageMap, context) { textOnly: true, }) } - - versions = page.applicableVersions } // Return only the props needed for the ProductSelectionCard, since // that's the only place this is ever used. return { id, name, - href: href.replace(`/${lang}/`, '/'), - versions, + href, external, } } @@ -59,9 +82,9 @@ export async function getProductGroups(pageMap, lang, context) { icon: group.icon || null, octicon: group.octicon || null, // Typically the children are product IDs, but we support deeper page paths too - children: await Promise.all( - group.children.map((id) => getPage(id, lang, pageMap, context)), - ), + children: ( + await Promise.all(group.children.map((id) => getPage(id, lang, pageMap, context))) + ).filter(Boolean), } }), ) diff --git a/src/landings/components/ProductSelectionCard.tsx b/src/landings/components/ProductSelectionCard.tsx index e864739a22..5f53fb7772 100644 --- a/src/landings/components/ProductSelectionCard.tsx +++ b/src/landings/components/ProductSelectionCard.tsx @@ -1,9 +1,6 @@ -import { ProductT, useMainContext } from 'components/context/MainContext' import type { ProductGroupT } from 'src/landings/components/ProductSelections' import React from 'react' -import { useRouter } from 'next/router' -import { useVersion } from 'components/hooks/useVersion' import { Link } from 'components/Link' import * as Octicons from '@primer/octicons-react' import { LinkExternalIcon } from '@primer/octicons-react' @@ -13,26 +10,10 @@ type ProductSelectionCardProps = { } export const ProductSelectionCard = ({ group }: ProductSelectionCardProps) => { - const router = useRouter() - const { currentVersion } = useVersion() - const { isFPT } = useMainContext() - - function href(product: ProductT) { - return `${!product.external ? `/${router.locale}` : ''}${ - product.versions?.includes(currentVersion) && !isFPT - ? `/${currentVersion}/${product.id}` - : product.href - }` - } - const groupIcon = { height: '22px', } - function showProduct(product: ProductT) { - return isFPT || product.versions?.includes(currentVersion) || product.external - } - function icon(group: ProductGroupT) { if (group.icon) { return ( @@ -67,16 +48,9 @@ export const ProductSelectionCard = ({ group }: ProductSelectionCardProps) => {
    {group.children.map((product) => { - if (!showProduct(product)) { - return null - } - return (
  • - + {product.name} {product.external && (