only include productGroups in main context on homepage (#31640)
This commit is contained in:
@@ -13,13 +13,6 @@ export type ProductT = {
|
||||
versions?: Array<string>
|
||||
}
|
||||
|
||||
export type ProductGroupT = {
|
||||
name: string
|
||||
icon: string
|
||||
octicon: string
|
||||
children: Array<ProductT>
|
||||
}
|
||||
|
||||
type VersionItem = {
|
||||
// free-pro-team@latest, enterprise-cloud@latest, enterprise-server@3.3 ...
|
||||
version: string
|
||||
@@ -77,7 +70,6 @@ export type MainContextT = {
|
||||
article?: BreadcrumbT
|
||||
}
|
||||
activeProducts: Array<ProductT>
|
||||
productGroups: Array<ProductGroupT>
|
||||
communityRedirect: {
|
||||
name: string
|
||||
href: string
|
||||
@@ -137,7 +129,6 @@ export const getMainContext = async (req: any, res: any): Promise<MainContextT>
|
||||
return {
|
||||
breadcrumbs: req.context.breadcrumbs || {},
|
||||
activeProducts: req.context.activeProducts,
|
||||
productGroups: req.context.productGroups,
|
||||
communityRedirect: req.context.page?.communityRedirect || {},
|
||||
currentProduct: req.context.productMap[req.context.currentProduct] || null,
|
||||
currentLayoutName: req.context.currentLayoutName,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ProductT, ProductGroupT, useMainContext } from 'components/context/MainContext'
|
||||
import { ProductT, useMainContext } from 'components/context/MainContext'
|
||||
import type { ProductGroupT } from 'components/homepage/ProductSelections'
|
||||
|
||||
import React from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
import { useMainContext } from 'components/context/MainContext'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import type { ProductT } from 'components/context/MainContext'
|
||||
import { ProductSelectionCard } from './ProductSelectionCard'
|
||||
|
||||
export const ProductSelections = () => {
|
||||
const { productGroups } = useMainContext()
|
||||
export type ProductGroupT = {
|
||||
name: string
|
||||
icon: string
|
||||
octicon: string
|
||||
children: Array<ProductT>
|
||||
}
|
||||
|
||||
type Props = {
|
||||
productGroups: Array<ProductGroupT>
|
||||
}
|
||||
|
||||
export const ProductSelections = ({ productGroups }: Props) => {
|
||||
return (
|
||||
<section className="container-xl pb-lg-4 mt-6 px-3 px-md-6" data-testid="product">
|
||||
<div className="">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import languages from '../lib/languages.js'
|
||||
import enterpriseServerReleases from '../lib/enterprise-server-releases.js'
|
||||
import { allVersions } from '../lib/all-versions.js'
|
||||
import { productMap, getProductGroups } from '../lib/all-products.js'
|
||||
import { productMap } from '../lib/all-products.js'
|
||||
import pathUtils from '../lib/path-utils.js'
|
||||
import productNames from '../lib/product-names.js'
|
||||
import warmServer from '../lib/warm-server.js'
|
||||
@@ -39,7 +39,6 @@ export default async function contextualize(req, res, next) {
|
||||
req.context.currentProduct = getProductStringFromPath(req.pagePath)
|
||||
req.context.currentCategory = getCategoryStringFromPath(req.pagePath)
|
||||
req.context.productMap = productMap
|
||||
req.context.productGroups = getProductGroups(pageMap, req.language)
|
||||
req.context.activeProducts = activeProducts
|
||||
req.context.allVersions = allVersions
|
||||
req.context.currentPathWithoutLanguage = getPathWithoutLanguage(req.pagePath)
|
||||
|
||||
32
middleware/contextualizers/product-groups.js
Normal file
32
middleware/contextualizers/product-groups.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { getProductGroups } from '../../lib/all-products.js'
|
||||
import warmServer from '../../lib/warm-server.js'
|
||||
import { languageKeys } from '../../lib/languages.js'
|
||||
import { allVersionKeys } from '../../lib/all-versions.js'
|
||||
|
||||
const isHomepage = (path) => {
|
||||
const split = path.split('/')
|
||||
// E.g. `/foo` but not `foo/bar` or `foo/`
|
||||
if (split.length === 2 && split[1] && !split[0]) {
|
||||
return languageKeys.includes(split[1])
|
||||
}
|
||||
// E.g. `/foo/possiblyproductname` but not `foo/possiblyproductname` or
|
||||
// `/foo/something/`
|
||||
if (split.length === 3 && !split[0] && split[2]) {
|
||||
return allVersionKeys.includes(split[2])
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export default async function productGroups(req, res, next) {
|
||||
// It's important to use `req.pathPage` instead of `req.path` because
|
||||
// the request could be the client-side routing from Next where the URL
|
||||
// might be something like `/_next/data/foo/bar.json` which is translated,
|
||||
// in another middleware, to what it would equate to if it wasn't
|
||||
// client-side routing.
|
||||
if (isHomepage(req.pagePath)) {
|
||||
const { pages } = await warmServer()
|
||||
req.context.productGroups = getProductGroups(pages, req.language)
|
||||
}
|
||||
|
||||
return next()
|
||||
}
|
||||
@@ -45,6 +45,7 @@ import genericToc from './contextualizers/generic-toc.js'
|
||||
import breadcrumbs from './contextualizers/breadcrumbs.js'
|
||||
import features from './contextualizers/features.js'
|
||||
import productExamples from './contextualizers/product-examples.js'
|
||||
import productGroups from './contextualizers/product-groups.js'
|
||||
import featuredLinks from './featured-links.js'
|
||||
import learningTrack from './learning-track.js'
|
||||
import next from './next.js'
|
||||
@@ -267,6 +268,7 @@ export default function (app) {
|
||||
app.use(asyncMiddleware(instrument(breadcrumbs, './contextualizers/breadcrumbs')))
|
||||
app.use(instrument(features, './contextualizers/features'))
|
||||
app.use(asyncMiddleware(instrument(productExamples, './contextualizers/product-examples')))
|
||||
app.use(asyncMiddleware(instrument(productGroups, './contextualizers/product-groups')))
|
||||
|
||||
app.use(asyncMiddleware(instrument(featuredLinks, './featured-links')))
|
||||
app.use(asyncMiddleware(instrument(learningTrack, './learning-track')))
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { GetServerSideProps } from 'next'
|
||||
import React from 'react'
|
||||
import type { GetServerSideProps } from 'next'
|
||||
|
||||
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
|
||||
|
||||
import React from 'react'
|
||||
import { DefaultLayout } from 'components/DefaultLayout'
|
||||
import { useTranslation } from 'components/hooks/useTranslation'
|
||||
import { ArticleList } from 'components/landing/ArticleList'
|
||||
import { HomePageHero } from 'components/homepage/HomePageHero'
|
||||
import type { ProductGroupT } from 'components/homepage/ProductSelections'
|
||||
import { ProductSelections } from 'components/homepage/ProductSelections'
|
||||
|
||||
type FeaturedLink = {
|
||||
@@ -19,13 +20,23 @@ type Props = {
|
||||
mainContext: MainContextT
|
||||
popularLinks: Array<FeaturedLink>
|
||||
gettingStartedLinks: Array<FeaturedLink>
|
||||
productGroups: Array<ProductGroupT>
|
||||
}
|
||||
|
||||
export default function MainHomePage({ mainContext, gettingStartedLinks, popularLinks }: Props) {
|
||||
export default function MainHomePage({
|
||||
mainContext,
|
||||
gettingStartedLinks,
|
||||
popularLinks,
|
||||
productGroups,
|
||||
}: Props) {
|
||||
return (
|
||||
<MainContext.Provider value={mainContext}>
|
||||
<DefaultLayout>
|
||||
<HomePage gettingStartedLinks={gettingStartedLinks} popularLinks={popularLinks} />
|
||||
<HomePage
|
||||
gettingStartedLinks={gettingStartedLinks}
|
||||
popularLinks={popularLinks}
|
||||
productGroups={productGroups}
|
||||
/>
|
||||
</DefaultLayout>
|
||||
</MainContext.Provider>
|
||||
)
|
||||
@@ -34,15 +45,16 @@ export default function MainHomePage({ mainContext, gettingStartedLinks, popular
|
||||
type HomePageProps = {
|
||||
popularLinks: Array<FeaturedLink>
|
||||
gettingStartedLinks: Array<FeaturedLink>
|
||||
productGroups: Array<ProductGroupT>
|
||||
}
|
||||
function HomePage(props: HomePageProps) {
|
||||
const { gettingStartedLinks, popularLinks } = props
|
||||
const { gettingStartedLinks, popularLinks, productGroups } = props
|
||||
const { t } = useTranslation(['toc'])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HomePageHero />
|
||||
<ProductSelections />
|
||||
<ProductSelections productGroups={productGroups} />
|
||||
<div className="mt-6 px-3 px-md-6 container-xl">
|
||||
<div className="container-xl">
|
||||
<div className="gutter gutter-xl-spacious clearfix">
|
||||
@@ -67,6 +79,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (context) =>
|
||||
return {
|
||||
props: {
|
||||
mainContext: await getMainContext(req, res),
|
||||
productGroups: req.context.productGroups,
|
||||
gettingStartedLinks: req.context.featuredLinks.gettingStarted.map(
|
||||
({ title, href, intro }: any) => ({ title, href, intro })
|
||||
),
|
||||
|
||||
31
tests/rendering/homepage.js
Normal file
31
tests/rendering/homepage.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import { expect, jest } from '@jest/globals'
|
||||
|
||||
import { getDOM } from '../helpers/e2etest.js'
|
||||
|
||||
describe('rendering the home page(s)', () => {
|
||||
jest.setTimeout(5 * 60 * 1000)
|
||||
|
||||
test('homepage has product links', async () => {
|
||||
const $ = await getDOM('/en')
|
||||
const products = $('[data-testid=product]')
|
||||
expect(products.length).toBe(1)
|
||||
})
|
||||
|
||||
test('homepage in non-default language has product links', async () => {
|
||||
const $ = await getDOM('/ja')
|
||||
const products = $('[data-testid=product]')
|
||||
expect(products.length).toBe(1)
|
||||
})
|
||||
|
||||
test('homepage in non-default product', async () => {
|
||||
const $ = await getDOM('/en/enterprise-cloud@latest')
|
||||
const products = $('[data-testid=product]')
|
||||
expect(products.length).toBe(1)
|
||||
})
|
||||
|
||||
test('homepage in non-default product in non-default language', async () => {
|
||||
const $ = await getDOM('/ja/enterprise-cloud@latest')
|
||||
const products = $('[data-testid=product]')
|
||||
expect(products.length).toBe(1)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user