-
Notifications
You must be signed in to change notification settings - Fork 5
feat(roadmap): add roadmap page with json data loading logic with sim… #215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
adrianboros
wants to merge
58
commits into
main
Choose a base branch
from
feat/roadmap-page
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
58 commits
Select commit
Hold shift + click to select a range
f9e0531
feat(roadmap): add roadmap page with json data loading logic with sim…
adrianboros ae54895
feat(roadmap): bun format fix
adrianboros 3c84220
fix(roadmap-page): add env var
adrianboros 40744a8
feat(roadmap): update timeline to group projects by teams, and color …
adrianboros 6f039c3
fix(roadmap): lint fix
adrianboros a6c6466
fix(roadmap): have teams name stay visible on the screen
adrianboros f4220eb
chore(deps): add netlify adapter, blobs, functions, and linear sdk
adrianboros 44feb04
build(astro): switch to hybrid SSR mode with Netlify adapter
adrianboros f5fc50c
feat(linear): add Linear client and snapshot builder
adrianboros e020d0d
feat(functions): add scheduled Linear sync function (every 12h)
adrianboros ead28ca
feat(functions): add manual sync endpoint (POST /api/sync)
adrianboros 60321f3
feat(roadmap): switch roadmap page to SSR, read from Netlify Blobs
adrianboros a47915b
chore(config): remove ROADMAP_API_URL, add Linear and Netlify env vars
adrianboros d3a284b
chore(deps): downgrade astro netlify adaptor to work with astro v5
adrianboros c9e7280
chore(deps): add deno.lock and .netlify folder
adrianboros a30cf31
build(astro): "hybrid" was removed in Astro 5.x and needs to be chang…
adrianboros 087d867
Merge branch 'main' into feat/roadmap-page
adrianboros ddd5462
chore(deps): fix packages after merge from main
adrianboros 502b774
chore(deps): lint issues
adrianboros 161a3a1
fix(roadmap-page): lighten up the teams colors
adrianboros 62178ec
fix(roadmap-page): mobile view with tap on milestones to view titles
adrianboros 90b76fb
fix(linear): fix type error on build linear data snapshot
adrianboros 0d180ea
fix(roadmap-page): remove logs, lint fixes and small styling update
adrianboros 5c70d06
fix(roadmap-page): remove project links completely from the page
adrianboros 5c75c3d
chore(deps): update netlify.toml to add the roadmap redirects before …
adrianboros 2843382
chore(deps): netlify.toml redirect cleanup
adrianboros f5deb0f
chore(deps): netlify.toml redirect cleanup wip and bun format
adrianboros 16fe966
chore(deps): fix lint issues
adrianboros 426a64f
Merge branch 'main' into feat/roadmap-page
adrianboros 3b73457
chore(deps): netlify redirect issue
adrianboros d2fb0db
chore(deps): netlify redirect issue
adrianboros 0b243eb
chore(deps): netlify redirect issue, revert
adrianboros 0384ea6
fix(roadmap-page): fix board over header menu issue
adrianboros 0615999
fix(roadmap-page): refactor to have sticky board header
adrianboros d62f276
fix(linear-snapshot): filter out completed and cancelled projects
adrianboros 194d9fd
fix(roadmap-page): team/projects column updates
adrianboros 10bda5e
fix(roadmap-page): team/projects column updates
adrianboros 256b57e
fix(linear): exclude projects based on non-public label
adrianboros 787d6c8
chore(deps): netlify redirect issue
adrianboros 092c6e4
fix(roadmap-page): date fallback fix
adrianboros ec84146
chore(deps): env params refactoring
adrianboros 4d05eb3
fix(roadmap-page): header horizontal scrooling bidirectional sync wit…
adrianboros 2adaa9e
fix(roadmap-page): set default team and project colors constants
adrianboros 4202ea4
fix(roadmap-page): refactor roadmap board component break out utility…
adrianboros e38e3ed
fix(roadmap-page): add utility attributes for screen readers
adrianboros 5f2514e
chore(deps): build fix
adrianboros 9086f9c
chore(deps): lint fix
adrianboros 56a2c34
fix(linear-snapshot): remove unused lastErr
adrianboros e32ee21
fix(linear-snapshot): remove initial/bad archived project filter
adrianboros a2fa793
fix(linear): requirement update - include only projects that have pub…
adrianboros c978210
chore(deps): lint fix
adrianboros e684349
chore(netlify): dev env settings fixes
adrianboros f3d3769
fix(linear): refactor type definitions merge Roadmap and Board types
adrianboros 8a6b06d
chore(deps): lint fix
adrianboros c89fe2a
fix(linear): add generatedAt at the bottom of the page and remove las…
adrianboros 031261c
fix(netliffy): extract purge cache utility function
adrianboros 9dd3a1b
fix(netlify): add rate limiting on the endpoint and timing attacks im…
adrianboros a14d9d9
fix(roadmap-page): add a console error in case roadmap snapshot it no…
adrianboros File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # Variables marked "required" will cause a build/runtime error if missing in production. | ||
| # To build locally without these keys, run: bun run astro build -- --mode development | ||
|
|
||
| # ----------------------------------------------------------------------------- | ||
| # Linear (required) | ||
| # ----------------------------------------------------------------------------- | ||
|
|
||
| # Linear API key — used by sync functions to fetch roadmap data from Linear | ||
| # Get from: Linear → Settings → API → Personal API keys | ||
| LINEAR_API_KEY=lin_api_... | ||
|
|
||
| # Linear custom view ID containing the roadmap projects (required) | ||
| LINEAR_CUSTOM_VIEW_ID=27df73bc-50ec-4fc1-bbb2-d906236a5bbc | ||
|
|
||
| # ----------------------------------------------------------------------------- | ||
| # Sync API (required) | ||
| # ----------------------------------------------------------------------------- | ||
|
|
||
| # Bearer token for POST /api/sync (manual sync trigger) — set to any strong secret | ||
| API_SECRET= | ||
|
|
||
| # ----------------------------------------------------------------------------- | ||
| # Netlify (optional — used for CDN cache purging after sync) | ||
| # ----------------------------------------------------------------------------- | ||
|
|
||
| # Netlify Personal Access Token | ||
| # Get from: Netlify UI → User Settings → Applications → Personal access tokens | ||
| NETLIFY_API_TOKEN= | ||
|
|
||
| # Netlify Site ID — auto-injected by Netlify in production and by `netlify dev` after `netlify link` | ||
| # Set manually only if running sync functions outside of the Netlify CLI | ||
| # NETLIFY_SITE_ID= |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| import { timingSafeEqual } from 'crypto' | ||
| import { getStore } from '@netlify/blobs' | ||
| import { buildSnapshot } from '../../src/linear/build-snapshot.js' | ||
| import type { Context } from '@netlify/functions' | ||
| import { API_SECRET } from '../../src/config.js' | ||
| import { purgeRoadmapCache } from './utils/purge-roadmap-cache.mts' | ||
|
|
||
| const FIVE_MINUTES_MS = 5 * 60 * 1000 | ||
| const RL_KEY = 'sync-rate-limit' | ||
|
|
||
| export default async function handler( | ||
| req: Request, | ||
| _ctx: Context | ||
| ): Promise<Response> { | ||
| const authHeader = req.headers.get('authorization') ?? '' | ||
| const token = authHeader.replace(/^Bearer\s+/i, '') | ||
|
|
||
| if (!API_SECRET) { | ||
| return new Response(JSON.stringify({ error: 'Unauthorized' }), { | ||
| status: 401, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| } | ||
|
adrianboros marked this conversation as resolved.
|
||
|
|
||
| const secretBuf = Buffer.from(API_SECRET) | ||
| const tokenBuf = Buffer.from(token) | ||
| const authorized = | ||
| tokenBuf.length === secretBuf.length && timingSafeEqual(tokenBuf, secretBuf) | ||
|
|
||
| if (!authorized) { | ||
| return new Response(JSON.stringify({ error: 'Unauthorized' }), { | ||
| status: 401, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| }) | ||
| } | ||
|
|
||
| const store = getStore('roadmap') | ||
|
|
||
| const lastSync = (await store.get(RL_KEY, { type: 'json' })) as { | ||
| ts: number | ||
| } | null | ||
| if (lastSync && Date.now() - lastSync.ts < FIVE_MINUTES_MS) { | ||
| const retryAfter = Math.ceil( | ||
| (FIVE_MINUTES_MS - (Date.now() - lastSync.ts)) / 1000 | ||
| ) | ||
| return new Response( | ||
| JSON.stringify({ error: 'Too Many Requests', retryAfter }), | ||
| { | ||
| status: 429, | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| 'Retry-After': String(retryAfter) | ||
| } | ||
| } | ||
| ) | ||
| } | ||
| await store.setJSON(RL_KEY, { ts: Date.now() }) | ||
|
|
||
| const snapshot = await buildSnapshot() | ||
|
|
||
| await store.setJSON('roadmap-snapshot', snapshot) | ||
|
|
||
| await purgeRoadmapCache() | ||
|
|
||
| return new Response( | ||
| JSON.stringify({ ok: true, generatedAt: snapshot.generatedAt }), | ||
| { | ||
| status: 200, | ||
| headers: { 'Content-Type': 'application/json' } | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| export const config = { | ||
| path: '/api/sync' | ||
| } | ||
|
adrianboros marked this conversation as resolved.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| import { getStore } from '@netlify/blobs' | ||
| import { buildSnapshot } from '../../src/linear/build-snapshot.js' | ||
| import { purgeRoadmapCache } from './utils/purge-roadmap-cache.mts' | ||
|
|
||
| export default async function handler() { | ||
| const snapshot = await buildSnapshot() | ||
|
|
||
| const store = getStore('roadmap') | ||
| await store.setJSON('roadmap-snapshot', snapshot) | ||
|
|
||
| await purgeRoadmapCache() | ||
| } | ||
|
|
||
| export const config = { | ||
| schedule: '0 */12 * * *' | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { NETLIFY_SITE_ID, NETLIFY_API_TOKEN } from '../../../src/config.js' | ||
|
|
||
| export async function purgeRoadmapCache(): Promise<void> { | ||
| if (!NETLIFY_SITE_ID || !NETLIFY_API_TOKEN) return | ||
|
|
||
| await fetch('https://api.netlify.com/api/v1/purge', { | ||
| method: 'POST', | ||
| headers: { | ||
| Authorization: `Bearer ${NETLIFY_API_TOKEN}`, | ||
| 'Content-Type': 'application/json' | ||
| }, | ||
| body: JSON.stringify({ | ||
| site_id: NETLIFY_SITE_ID, | ||
| paths: ['/developers/roadmap'] | ||
| }) | ||
| }) | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { buildSnapshot } from '../src/linear/build-snapshot.ts' | ||
| import { getStore } from '@netlify/blobs' | ||
| import { NETLIFY_SITE_ID, NETLIFY_API_TOKEN } from '../src/config.js' | ||
|
|
||
| if (!NETLIFY_SITE_ID || !NETLIFY_API_TOKEN) { | ||
| /* eslint-disable-next-line no-console */ | ||
| console.log('Skipping blob sync: missing env vars') | ||
| process.exit(0) | ||
| } | ||
|
|
||
| const snapshot = await buildSnapshot() | ||
| const store = getStore({ | ||
| name: 'roadmap', | ||
| siteID: NETLIFY_SITE_ID, | ||
| token: NETLIFY_API_TOKEN | ||
| }) | ||
| await store.setJSON('roadmap-snapshot', snapshot) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.