Skip to content

Commit 51c65e3

Browse files
sarahsCopilot
andauthored
Support data-driven tables (#57806)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 943b2e1 commit 51c65e3

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

data/tables/README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# Data-driven tables
2+
3+
## Overview
4+
5+
GitHub Docs uses YAML files to manage some complex reference tables instead of hard-to-maintain Markdown tables. This approach provides:
6+
7+
- **Maintainable format**: Stakeholders can easily update readable YAML files
8+
- **Single source of truth**: Centralized data prevents inconsistencies
9+
- **Accurate information**: Reduces errors and outdated content
10+
- **Self-service process**: Minimal engineering support needed
11+
12+
> **Important**: The `.yml` files in this directory are maintained **manually**. Tables that need automatic updates from external sources require engineering work.
13+
14+
## Table of contents
15+
16+
- [When to use this approach](#when-to-use-this-approach)
17+
- [How it works](#how-it-works)
18+
- [Step-by-step guide](#step-by-step-guide)
19+
- [Testing and validation](#testing-and-validation)
20+
- [Next steps](#next-steps)
21+
22+
## When to use this approach
23+
24+
Use data-driven tables when you have:
25+
- Complex reference tables with multiple columns
26+
- Data that needs regular updates by different stakeholders
27+
- Structured information that benefits from validation
28+
29+
## How it works
30+
31+
Every data-driven table needs **three files** that work together:
32+
33+
| File type | Location | Purpose |
34+
|-----------|----------|---------|
35+
| **Data file** | `data/tables/` | Stores the table content in YAML format |
36+
| **Content file** | `content/` | Displays the table using Liquid templating |
37+
| **Schema file** | `src/data-directory/lib/data-schemas/` | Validates the YAML structure |
38+
39+
**Estimated time**: 30-60 minutes for a new table
40+
41+
## Step-by-step guide
42+
43+
### Step 1: Create the data file
44+
45+
Create a new `.yml` file in `data/tables/` with a descriptive name.
46+
47+
**Copilot prompt template:**
48+
```
49+
Create a YAML structure that will allow me to generate a table that looks like:
50+
[describe your table headers, rows, and columns OR attach an example]
51+
52+
See src/secret-scanning/data/public-docs.yml for an example.
53+
```
54+
55+
### Step 2: Create the content display
56+
57+
In your content file, add Liquid code to render the table. Access your data at `{% data tables.TABLE_NAME %}` (where `TABLE_NAME` is your filename without `.yml`).
58+
59+
**Copilot prompt template:**
60+
```
61+
Create a Markdown table that is dynamically rendered using Liquid code.
62+
Pull data from data/tables/TABLE_NAME.yml.
63+
The table should look like: [describe your desired output OR attach an example]
64+
65+
See content/code-security/secret-scanning/introduction/supported-secret-scanning-patterns.md for an example.
66+
Liquid docs: https://shopify.github.io/liquid
67+
```
68+
69+
**💡 Tip**: Iterate between Steps 1 and 2 until the table renders correctly.
70+
71+
### Step 3: Create the schema file
72+
73+
Create a `.ts` file in `src/data-directory/lib/data-schemas/` with the same name as your YAML file.
74+
75+
**Copilot prompt template:**
76+
```
77+
Create a TypeScript schema following prior art under data-schemas that enforces
78+
the structure of the data/TABLE_NAME.yml file.
79+
80+
See src/data-directory/lib/data-schemas/learning-tracks.ts for an example.
81+
```
82+
83+
## Testing and validation
84+
85+
After creating all three files:
86+
87+
1. **Build the site**: Run `npm run build`
88+
2. **Test schemas**: Run `npm test -- src/data-directory/tests`
89+
3. **Fix any errors**: If you get failures in `src/data-directory/tests/data-schemas.js`:
90+
- Copy the error message
91+
- In VS Code Copilot Chat, type: "When I ran the schema test, I got this error:" and paste the error
92+
- Update your schema file based on Copilot's suggestions
93+
4. **Repeat testing** until all tests pass
94+
95+
## Next steps
96+
97+
Once your table is working and tests pass, create a pull request for review.
98+
99+
The `docs-engineering` team must review and approve your implementation.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { NextFunction, Response } from 'express'
2+
import { ExtendedRequest } from '@/types'
3+
import { getDeepDataByLanguage } from '@/data-directory/lib/get-data'
4+
5+
let tablesCache: Record<string, unknown> | null = null
6+
7+
// Lazy loading function
8+
const getTables = () => {
9+
if (!tablesCache) {
10+
// Keep product-name-heavy reference tables in English only for now
11+
tablesCache = getDeepDataByLanguage('tables', 'en')
12+
}
13+
return tablesCache
14+
}
15+
16+
/**
17+
* Middleware that loads data-driven table content into the request context.
18+
* Tables are sourced from YAML files in data/tables/ directory.
19+
*/
20+
export default async function dataTables(req: ExtendedRequest, res: Response, next: NextFunction) {
21+
if (!req.context) throw new Error('request not contextualized')
22+
23+
req.context.tables = getTables()
24+
25+
return next()
26+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
features:
2+
foo:
3+
name: 'Foo Feature'
4+
fptAndGhec: true
5+
ghes: false
6+
bar:
7+
name: 'Bar Feature'
8+
fptAndGhec: true
9+
ghes: true
10+
supported:
11+
BeepBoop:
12+
foo: 'supported'
13+
bar: 'not-supported'

src/frame/middleware/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import robots from './robots'
3535
import earlyAccessLinks from '@/early-access/middleware/early-access-links'
3636
import categoriesForSupport from './categories-for-support'
3737
import triggerError from '@/observability/middleware/trigger-error'
38+
import dataTables from '@/data-directory/middleware/data-tables'
3839
import secretScanning from '@/secret-scanning/middleware/secret-scanning'
3940
import ghesReleaseNotes from '@/release-notes/middleware/ghes-release-notes'
4041
import whatsNewChangelog from './context/whats-new-changelog'
@@ -256,6 +257,7 @@ export default function (app: Express) {
256257
app.head('/*path', fastHead)
257258

258259
// *** Preparation for render-page: contextualizers ***
260+
app.use(asyncMiddleware(dataTables))
259261
app.use(asyncMiddleware(secretScanning))
260262
app.use(asyncMiddleware(ghesReleaseNotes))
261263
app.use(asyncMiddleware(whatsNewChangelog))

0 commit comments

Comments
 (0)