Skip to content

Commit 997db12

Browse files
authored
Tighten up types used for landing pages (#56237)
1 parent d38bbab commit 997db12

File tree

7 files changed

+116
-41
lines changed

7 files changed

+116
-41
lines changed

src/frame/components/context/CategoryLandingContext.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import pick from 'lodash/pick'
21
import { createContext, useContext } from 'react'
32
import { LearningTrack } from './ArticleContext'
43
import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext'
5-
import { TocItem } from '@/landings/types'
4+
import type { TocItem } from '@/landings/types'
5+
import { mapRawTocItemToTocItem } from '@/landings/types'
66

77
export type CategoryLandingContextT = {
88
title: string
@@ -37,8 +37,8 @@ export const getCategoryLandingContextFromRequest = (req: any): CategoryLandingC
3737
productCallout: req.context.page.product || '',
3838
permissions: req.context.page.permissions || '',
3939
intro: req.context.page.intro,
40-
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map((obj: any) =>
41-
pick(obj, ['fullPath', 'title', 'intro', 'childTocItems']),
40+
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map(
41+
mapRawTocItemToTocItem,
4242
),
4343
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
4444
featuredLinks: getFeaturedLinksFromReq(req),

src/frame/components/context/TocLandingContext.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,15 @@
1-
import pick from 'lodash/pick'
21
import { createContext, useContext } from 'react'
32
import { LearningTrack } from './ArticleContext'
43
import { FeaturedLink, getFeaturedLinksFromReq } from '@/landings/components/ProductLandingContext'
5-
6-
export type TocItem = {
7-
fullPath: string
8-
title: string
9-
intro?: string
10-
}
4+
import type { SimpleTocItem } from '@/landings/types'
5+
import { mapRawTocItemToSimpleTocItem } from '@/landings/types'
116

127
export type TocLandingContextT = {
138
title: string
149
intro: string
1510
productCallout: string
1611
permissions: string
17-
tocItems: Array<TocItem>
12+
tocItems: Array<SimpleTocItem>
1813
variant?: 'compact' | 'expanded'
1914
featuredLinks: Record<string, Array<FeaturedLink>>
2015
renderedPage: string
@@ -39,8 +34,8 @@ export const getTocLandingContextFromRequest = (req: any): TocLandingContextT =>
3934
productCallout: req.context.page.product || '',
4035
permissions: req.context.page.permissions || '',
4136
intro: req.context.page.intro,
42-
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map((obj: any) =>
43-
pick(obj, ['fullPath', 'title', 'intro', 'childTocItems']),
37+
tocItems: (req.context.genericTocFlat || req.context.genericTocNested || []).map(
38+
mapRawTocItemToSimpleTocItem,
4439
),
4540
variant: req.context.genericTocFlat ? 'expanded' : 'compact',
4641
featuredLinks: getFeaturedLinksFromReq(req),

src/landings/components/ProductLandingContext.tsx

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
import { createContext, useContext } from 'react'
22
import pick from 'lodash/pick'
3-
4-
export type TocItem = {
5-
fullPath: string
6-
title: string
7-
intro?: string
8-
childTocItems?: Array<{
9-
fullPath: string
10-
title: string
11-
}>
12-
}
3+
import type { SimpleTocItem } from '@/landings/types'
134
export type FeaturedLink = {
145
title: string
156
href: string
@@ -60,7 +51,7 @@ export type ProductLandingContextT = {
6051
}>
6152
changelogUrl?: string
6253
whatsNewChangelog?: Array<{ href: string; title: string; date: string }>
63-
tocItems: Array<TocItem>
54+
tocItems: Array<SimpleTocItem>
6455
hasGuidesPage: boolean
6556
ghesReleases: Array<Release>
6657
}

src/landings/components/TableOfContents.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import cx from 'classnames'
33

44
import { ActionList } from '@primer/react'
55
import { Link } from '@/frame/components/Link'
6-
import type { TocItem } from '@/landings/components/ProductLandingContext'
6+
import type { TocItem } from '@/landings/types'
77

88
type Props = {
99
items: Array<TocItem>

src/landings/types.ts

Lines changed: 96 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,113 @@
1+
// Base type for all TOC items with core properties
12
export type BaseTocItem = {
23
fullPath: string
34
title: string
45
intro?: string
56
}
67

8+
// Valid octicon types that match the CookBookArticleCard component
9+
export type ValidOcticon =
10+
| 'code'
11+
| 'log'
12+
| 'terminal'
13+
| 'bug'
14+
| 'lightbulb'
15+
| 'gear'
16+
| 'rocket'
17+
| 'beaker'
18+
| 'copilot'
19+
| 'hubot'
20+
| 'book'
21+
| 'shield-lock'
22+
| 'lock'
23+
24+
// Extended type for child TOC items with additional metadata
725
export type ChildTocItem = BaseTocItem & {
8-
octicon?:
9-
| 'code'
10-
| 'log'
11-
| 'terminal'
12-
| 'bug'
13-
| 'lightbulb'
14-
| 'gear'
15-
| 'rocket'
16-
| 'beaker'
17-
| 'copilot'
18-
| 'hubot'
19-
| 'book'
26+
octicon?: ValidOcticon
2027
category?: string[]
2128
complexity?: string[]
2229
industry?: string[]
2330
}
2431

32+
// Main TOC item type that can contain children
2533
export type TocItem = BaseTocItem & {
2634
childTocItems?: ChildTocItem[]
35+
octicon?: ValidOcticon
36+
category?: string[]
37+
complexity?: string[]
38+
industry?: string[]
2739
}
2840

41+
// Type alias for article card components
2942
export type ArticleCardItems = ChildTocItem[]
43+
44+
// Raw TOC type that matches the actual data structure from getTocItems()
45+
// This includes all properties that may be present in the source data
46+
export type RawTocItem = {
47+
title: string
48+
fullPath: string
49+
intro: string | null
50+
octicon: string | null
51+
category: string[] | null
52+
complexity: string[] | null
53+
industry: string[] | null
54+
childTocItems: RawTocItem[]
55+
}
56+
57+
// Helper function to validate and cast octicon values
58+
export function isValidOcticon(octicon: string | null): octicon is ValidOcticon {
59+
const validOcticons: ValidOcticon[] = [
60+
'code',
61+
'log',
62+
'terminal',
63+
'bug',
64+
'lightbulb',
65+
'gear',
66+
'rocket',
67+
'beaker',
68+
'copilot',
69+
'hubot',
70+
'book',
71+
'shield-lock',
72+
'lock',
73+
]
74+
return octicon !== null && validOcticons.includes(octicon as ValidOcticon)
75+
}
76+
77+
// Simplified TOC item type for basic landing pages that don't need extended metadata
78+
export type SimpleTocItem = {
79+
fullPath: string
80+
title: string
81+
intro?: string
82+
childTocItems?: Array<{
83+
fullPath: string
84+
title: string
85+
}>
86+
}
87+
88+
// Reusable mapper function to convert RawTocItem to TocItem with full metadata
89+
export function mapRawTocItemToTocItem(raw: RawTocItem): TocItem {
90+
return {
91+
fullPath: raw.fullPath,
92+
title: raw.title,
93+
intro: raw.intro || undefined,
94+
octicon: isValidOcticon(raw.octicon) ? raw.octicon : undefined,
95+
category: raw.category || undefined,
96+
complexity: raw.complexity || undefined,
97+
industry: raw.industry || undefined,
98+
childTocItems: raw.childTocItems?.map(mapRawTocItemToTocItem),
99+
}
100+
}
101+
102+
// Reusable mapper function to convert RawTocItem to SimpleTocItem
103+
export function mapRawTocItemToSimpleTocItem(raw: RawTocItem): SimpleTocItem {
104+
return {
105+
fullPath: raw.fullPath,
106+
title: raw.title,
107+
intro: raw.intro || undefined,
108+
childTocItems: raw.childTocItems?.map((child) => ({
109+
fullPath: child.fullPath,
110+
title: child.title,
111+
})),
112+
}
113+
}

src/rest/pages/category.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ import {
1515
import type { MiniTocItem } from '@/frame/components/context/ArticleContext'
1616
import {
1717
getTocLandingContextFromRequest,
18-
TocItem,
1918
TocLandingContext,
2019
TocLandingContextT,
2120
} from '@/frame/components/context/TocLandingContext'
21+
import type { TocItem } from '@/landings/types'
2222
import { TocLanding } from '@/landings/components/TocLanding'
2323

2424
type MinitocItemsT = {

src/types.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Request } from 'express'
22
import type { Failbot } from '@github/failbot'
33

44
import type enterpriseServerReleases from '@/versions/lib/enterprise-server-releases.d.ts'
5+
import type { ValidOcticon } from '@/landings/types'
56

67
// Throughout our codebase we "extend" the Request object by attaching
78
// things to it. For example `req.context = { currentCategory: 'foo' }`.
@@ -239,8 +240,12 @@ type Breadcrumb = {
239240
export type ToC = {
240241
title: string
241242
fullPath: string
242-
intro: string
243-
childTocItems: ToC[] | null
243+
intro: string | null
244+
octicon: ValidOcticon | null
245+
category: string[] | null
246+
complexity: string[] | null
247+
industry: string[] | null
248+
childTocItems: ToC[]
244249
}
245250

246251
export type GHESRelease = {

0 commit comments

Comments
 (0)