From a5fcf2bdebc9ef136ae7286d97fd615ad7be12f1 Mon Sep 17 00:00:00 2001 From: Lukas Bresser Date: Thu, 10 Sep 2026 07:59:17 +0000 Subject: [PATCH] feat: restore public focus-area field velocity when ready --- scripts/velocity/field-velocity-panel.test.mjs | 15 ++++++++++----- scripts/velocity/preview-only.test.mjs | 18 ++---------------- src/app/areas/[slug]/page.tsx | 4 +++- src/app/areas/economies-governance/page.tsx | 4 ++-- 4 files changed, 17 insertions(+), 24 deletions(-) diff --git a/scripts/velocity/field-velocity-panel.test.mjs b/scripts/velocity/field-velocity-panel.test.mjs index 7909f921..62fc8732 100644 --- a/scripts/velocity/field-velocity-panel.test.mjs +++ b/scripts/velocity/field-velocity-panel.test.mjs @@ -45,14 +45,19 @@ function elements(node) { } for (const { key, label } of FOCUS_AREAS) { - test(`${key} staged panel retains charts and selected-area methodology/toolkit links without public route wiring`, async (t) => { + test(`${key} overview includes the shared panel, original strategy and selected-area methodology/toolkit links`, async (t) => { assert.ok(existsSync('src/components/AreaFieldVelocity.tsx'), 'missing reusable area panel') t.mock.method(globalThis, 'fetch', async () => new Response(null, { status: 503 })) t.mock.method(console, 'warn', () => {}) const Panel = source('components/AreaFieldVelocity.tsx').default - // The component is retained for a later launch, but no public page mounts it. - // Public-route absence is covered separately by preview-only.test.mjs. - const panelTree = await Panel({ area: key }) + const Page = source(key === 'economies-governance' ? 'app/areas/economies-governance/page.tsx' : 'app/areas/[slug]/page.tsx').default + const tree = await Page({ params: Promise.resolve({ slug: key }) }) + const children = elements(tree) + const panel = children.find(el => el.type === Panel) + assert.ok(panel, `${key} page does not mount shared panel`) + assert.equal(panel.props.area, key) + assert.ok(children.some(el => el.props.id === 'opportunity-spaces'), 'existing strategy preserved') + const panelTree = await Panel(panel.props) if (key === 'economies-governance') { assert.deepEqual(elements(panelTree).find(el => el.type === Dashboard).props.liveOutputs, {}, 'area panel must retain the overview live-output channel even when providers are unavailable') } @@ -64,7 +69,7 @@ for (const { key, label } of FOCUS_AREAS) { assert.match(html, /id="field-velocity"/) assert.ok(html.includes(`${label} field velocity`)) - + assert.ok(tree.props.className.includes('area-overview')) assert.ok(panelTree.props.className.includes('area-field-velocity')) assert.ok(panelTree.props.className.includes(key === 'neurotech' ? 'bg-gray-100' : 'bg-gray-200')) assert.doesNotMatch(panelTree.props.className, /border-y|px-4|bg-gray-50/) diff --git a/scripts/velocity/preview-only.test.mjs b/scripts/velocity/preview-only.test.mjs index 731591cc..3048ec47 100644 --- a/scripts/velocity/preview-only.test.mjs +++ b/scripts/velocity/preview-only.test.mjs @@ -4,7 +4,6 @@ import React from 'react' import { readFileSync } from 'node:fs' import { source } from './test-source-loader.mjs' -const Panel = source('components/AreaFieldVelocity.tsx').default const Dashboard = source('components/ImpactDashboardV2.tsx').default const Methodology = source('components/MeasuringQuestionsV2.tsx').default const { FOCUS_AREAS, FIELD_VELOCITY_OVERVIEW } = source('lib/field-velocity.ts') @@ -19,21 +18,8 @@ function offlineProviders(t) { t.mock.method(console, 'warn', () => {}) } -for (const { key } of FOCUS_AREAS) { - test(`${key} public detail keeps existing content but does not mount field velocity or preview links`, async (t) => { - offlineProviders(t) - const route = key === 'economies-governance' ? 'app/areas/economies-governance/page.tsx' : 'app/areas/[slug]/page.tsx' - const Page = source(route).default - const nodes = elements(await Page({ params: Promise.resolve({ slug: key }) })) - assert.ok(!nodes.some(node => node.type === Panel || node.type === Dashboard || node.type === Methodology), 'unreleased field velocity must not mount on public pages') - assert.ok(!nodes.some(node => node.props.id === 'field-velocity')) - assert.ok(!nodes.some(node => /impact-preview|#fv\/|#field-velocity|#methodology|#toolkit/.test(node.props.href ?? '')), 'no discovery links to the unlisted preview') - assert.ok(nodes.some(node => node.props.id === 'opportunity-spaces'), 'original strategy remains') - const existingLink = key === 'economies-governance' ? '/areas/economies-governance/projects/' : '/insights/' - assert.ok(nodes.some(node => node.props.href === existingLink), 'original Explore/Insights content remains') - assert.doesNotMatch(readFileSync(`src/${route}`, 'utf8'), /from ['"]@\/(?:components\/(?:AreaFieldVelocity|ImpactDashboardV2|MeasuringQuestionsV2)|lib\/field-velocity[^'"]*)['"]/, 'public routes must not load field-velocity modules') - }) -} +// Public detail mounting is covered by field-velocity-panel.test.mjs. +// The cross-field overview itself keeps its existing unlisted route. test('the exact unlisted overview retains all fields, charts, methodology and noindex metadata', async (t) => { offlineProviders(t) diff --git a/src/app/areas/[slug]/page.tsx b/src/app/areas/[slug]/page.tsx index a581a5f7..b119b966 100644 --- a/src/app/areas/[slug]/page.tsx +++ b/src/app/areas/[slug]/page.tsx @@ -1,4 +1,6 @@ import type { Metadata } from 'next' +import AreaFieldVelocity from '@/components/AreaFieldVelocity' +import { isFocusAreaKey } from '@/lib/field-velocity-data' import EditPageButton from '@/components/EditPageButton' import { PageEditHistoryByline } from '@/components/EditHistoryByline' @@ -287,7 +289,7 @@ export default async function AreaPage({ params }: Props) { )} - {/* Field velocity is preview-only until a separate public launch. */} + {isFocusAreaKey(slug) && } {/* Insights — latest posts, publications, and talks for this focus area */} {areaInsights.length > 0 && ( diff --git a/src/app/areas/economies-governance/page.tsx b/src/app/areas/economies-governance/page.tsx index 854bb5d5..0fb3729f 100644 --- a/src/app/areas/economies-governance/page.tsx +++ b/src/app/areas/economies-governance/page.tsx @@ -1,6 +1,6 @@ import Link from 'next/link' import type { Metadata } from 'next' - +import AreaFieldVelocity from '@/components/AreaFieldVelocity' import EditPageButton from '@/components/EditPageButton' import { PageEditHistoryByline } from '@/components/EditHistoryByline' import AuthorCard from '@/components/AuthorCard' @@ -255,7 +255,7 @@ export default async function FA2MainPage() { - {/* Field velocity is preview-only until a separate public launch. */} + {/* Explore */}

Explore