From 01b7295daa754405a4e211fa8e86901e190e2765 Mon Sep 17 00:00:00 2001 From: Ajax Davis Date: Tue, 20 Jan 2026 12:54:01 +1000 Subject: [PATCH] fix: resolve build errors and clean up scenario page - Remove undefined variable reference (run.conversation) in header - Extract ExpandedRunDetails component to reduce JSX nesting - Fix vitest configs: rename to .mjs and add ESM-compatible __dirname - Inline tailwind base config to avoid module resolution issues - Remove unused imports (Streamdown, viewMode state) This fixes the Turbopack parsing error that was preventing the build. --- apps/web/next-env.d.ts | 2 +- apps/web/package.json | 4 +- .../scenarios/[id]/ExpandedRunDetails.tsx | 140 +++++++++++ .../[slug]/scenarios/[id]/page.tsx | 231 +----------------- apps/web/vitest.config.mjs | 22 ++ apps/web/vitest.integration.config.mjs | 27 ++ 6 files changed, 202 insertions(+), 224 deletions(-) create mode 100644 apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/ExpandedRunDetails.tsx create mode 100644 apps/web/vitest.config.mjs create mode 100644 apps/web/vitest.integration.config.mjs diff --git a/apps/web/next-env.d.ts b/apps/web/next-env.d.ts index c4b7818..9edff1c 100644 --- a/apps/web/next-env.d.ts +++ b/apps/web/next-env.d.ts @@ -1,6 +1,6 @@ /// /// -import "./.next/dev/types/routes.d.ts"; +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/web/package.json b/apps/web/package.json index 1f21a82..d4be2fe 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -12,8 +12,8 @@ "clean": "rm -rf .next .turbo", "test": "vitest run", "test:watch": "vitest", - "test:integration": "INTEGRATION_TESTS=true vitest run --config vitest.integration.config.ts", - "test:integration:watch": "INTEGRATION_TESTS=true vitest --config vitest.integration.config.ts", + "test:integration": "INTEGRATION_TESTS=true vitest run --config vitest.integration.config.mjs", + "test:integration:watch": "INTEGRATION_TESTS=true vitest --config vitest.integration.config.mjs", "test:setup-credentials": "tsx src/test/integration/_helpers/setup-test-credentials.ts", "test:setup-openai-key": "tsx src/test/integration/_helpers/setup-openai-key.ts", "test:cleanup-orphans": "tsx src/test/integration/_helpers/cleanup-orphans.ts", diff --git a/apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/ExpandedRunDetails.tsx b/apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/ExpandedRunDetails.tsx new file mode 100644 index 0000000..f24ca8f --- /dev/null +++ b/apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/ExpandedRunDetails.tsx @@ -0,0 +1,140 @@ +import type { ScenarioRun } from './page'; + +interface ExpandedRunDetailsProps { + run: ScenarioRun; +} + +export function ExpandedRunDetails({ run }: ExpandedRunDetailsProps) { + return ( +
+
+ {/* Evaluator */} + {run.evaluator?.verdict && ( +
+

+ LLM Evaluation +

+
+ {run.evaluator.model && {run.evaluator.model}} +
+ {run.evaluator?.reason && ( +

{run.evaluator.reason}

+ )} +
+ )} + + {/* Usage Stats */} +
+

+ Usage +

+ {run.usage ? ( +
+
+ Duration:{' '} + + {run.usage?.executionTimeMs + ? `${Math.floor(run.usage.executionTimeMs / 1000)}s` + : '—'} + +
+
+ Tokens:{' '} + + {run.usage?.totalTokens?.toLocaleString() || '—'} + +
+
+ Retries:{' '} + {run.retryCount || 0} +
+
+ ) : ( +
No usage data available
+ )} +
+
+ + {/* Output (if owner) */} + {run.output && ( +
+

+ Output +

+
+            {run.output}
+          
+
+ )} + + {/* Error Log (if owner and error) */} + {run.errorLog && ( +
+

+ Error Log +

+
+            {run.errorLog}
+          
+
+ )} + + {/* Conversation History */} + {run.conversation && ( +
+
+

+ Conversation History +

+
+
+ {run.conversation.map((msg) => ( +
+ {msg.role === 'USER' && ( +
+
+
{msg.content}
+
+
+ )} + {msg.role === 'ASSISTANT' && ( +
+ {msg.content && ( +
+
+
+ {msg.content} +
+
+
+ )} +
+ )} + {msg.role === 'TOOL' && ( +
+
+
+
+ {msg.toolName || 'Unknown Tool'} +
+ {msg.toolResult != null && ( +
+
+                              {typeof msg.toolResult === 'string'
+                                ? msg.toolResult
+                                : JSON.stringify(msg.toolResult, null, 2)}
+                            
+
+ )} +
+
+
+ )} +
+ ))} +
+
+ )} +
+ ); +} diff --git a/apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/page.tsx b/apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/page.tsx index 122bb4c..fd4c04e 100644 --- a/apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/page.tsx +++ b/apps/web/src/app/(profile)/[username]/collections/[slug]/scenarios/[id]/page.tsx @@ -6,10 +6,10 @@ import { Icon } from '@tpmjs/ui/Icon/Icon'; import Link from 'next/link'; import { notFound, useParams } from 'next/navigation'; import { useCallback, useEffect, useState } from 'react'; -import { Streamdown } from 'streamdown'; import { AppHeader } from '~/components/AppHeader'; +import { ExpandedRunDetails } from './ExpandedRunDetails'; -interface ScenarioRun { +export interface ScenarioRun { id: string; status: string; retryCount: number; @@ -167,7 +167,6 @@ export default function CollectionScenarioDetailPage(): React.ReactElement { const [isRunning, setIsRunning] = useState(false); const [runError, setRunError] = useState(null); const [expandedRunId, setExpandedRunId] = useState(null); - const [viewMode, setViewMode] = useState<'chat' | 'debug'>('chat'); const fetchScenario = useCallback(async () => { try { @@ -261,43 +260,13 @@ export default function CollectionScenarioDetailPage(): React.ReactElement { {/* Header */}
-
-

- {scenario.name || 'Unnamed Scenario'} -

- {scenario.description && ( -

{scenario.description}

- )} -
- {scenario.isOwner && ( - - )} - {scenario.isOwner && ( - - )} +
+

+ {scenario.name || 'Unnamed Scenario'} +

+ {scenario.description && ( +

{scenario.description}

+ )}
{scenario.isOwner && ( {/* Run Details (Expanded) */} - {expandedRunId === run.id && ( -
-
- {/* Evaluator */} - {run.evaluator?.verdict && ( -
-

- LLM Evaluation -

-
- - {run.evaluator.model && ( - - {run.evaluator.model} - - )} -
- {run.evaluator?.reason && ( -

- {run.evaluator.reason} -

- )} -
- )} - - {/* Usage Stats */} -
-

- Usage -

- {run.usage ? ( -
-
- Duration:{' '} - - {formatDuration(run.usage.executionTimeMs || null)} - -
-
- Tokens:{' '} - - {run.usage.totalTokens?.toLocaleString() || '—'} - -
-
- Retries:{' '} - {run.retryCount} -
-
- ) : ( -
- No usage data available -
- )} -
- - {/* Output (if owner) */} - {run.output && ( -
-

- Output -

-
-                                {run.output}
-                              
-
- )} - - {/* Error Log (if owner and error) */} - {run.errorLog && ( -
-

- Error Log -

-
-                                {run.errorLog}
-                              
-
- )} - - {/* Conversation History */} - {run.conversation && ( -
-
-

- Conversation History -

-
- - -
-
- {viewMode === 'debug' ? ( -
-
-
- Raw Messages ({run.conversation.length}) -
- -
-
-                                    {JSON.stringify(run.conversation, null, 2)}
-                                  
-
- ) : ( -
- {run.conversation.map((msg) => ( -
- {msg.role === 'USER' && ( -
-
-
- {msg.content} -
-
-
- )} - {msg.role === 'ASSISTANT' && ( -
- {msg.content && ( -
-
-
- {msg.content} -
-
-
- )} -
- )} - {msg.role === 'TOOL' && ( -
-
-
-
- {msg.toolName || 'Unknown Tool'} -
- {msg.toolResult && ( -
-
-                                                    {typeof msg.toolResult === 'string'
-                                                      ? msg.toolResult
-                                                      : JSON.stringify(msg.toolResult, null, 2)}
-                                                  
-
- )} -
-
-
- )} -
- ))} -
- )} -
- )} -
- )} + {expandedRunId === run.id && }
))}
diff --git a/apps/web/vitest.config.mjs b/apps/web/vitest.config.mjs new file mode 100644 index 0000000..ae04c3b --- /dev/null +++ b/apps/web/vitest.config.mjs @@ -0,0 +1,22 @@ +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { defineConfig } from 'vitest/config'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/**/*.test.ts'], + exclude: ['src/test/integration/**/*.test.ts', 'node_modules/**'], + setupFiles: ['./src/test/setup.ts'], + testTimeout: 30000, // 30s for API calls + }, + resolve: { + alias: { + '~': resolve(__dirname, './src'), + }, + }, +}); diff --git a/apps/web/vitest.integration.config.mjs b/apps/web/vitest.integration.config.mjs new file mode 100644 index 0000000..3ea45d4 --- /dev/null +++ b/apps/web/vitest.integration.config.mjs @@ -0,0 +1,27 @@ +import { resolve, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { defineConfig } from 'vitest/config'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['src/test/integration/**/*.integration.test.ts'], + setupFiles: ['./src/test/integration/setup-integration.ts'], + testTimeout: 60000, // 60s for API calls to production + // Run tests sequentially to avoid race conditions on shared test data + sequence: { + concurrent: false, + }, + // Fail fast on integration tests + bail: 5, + }, + resolve: { + alias: { + '~': resolve(__dirname, './src'), + }, + }, +});