Feat(webapp) AI screen UI improvements#3269
Conversation
|
WalkthroughAdds two new icon components (AIMetricsIcon, AIPromptsIcon) and two Tailwind color tokens (aiPrompts, aiMetrics). Introduces SpanHorizontalTimeline and extends several span/detail components (PromptSpanDetails, AISpanDetails, runs routing) to accept optional startTime and duration and conditionally render the timeline. Large prompts route refactor adds PromptCopyPopover, animated override banner, table-based generations view, and other UI/UX changes. Miscellaneous updates: CodeBlock and Resizable/ResizableHandle layout/styling changes, PageContainer accepts className, keyboard shortcut adjustments in multiple filters, TimeFilter shortcut integration with tooltip, and various icon replacements. Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
...es/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx (1)
1290-1300:⚠️ Potential issue | 🟠 MajorKeep the inspector selection in sync with the current generations list.
After refresh/polling updates the list,
selectedSpancan point at a span that is no longer present ingenerations. In that state the table shows no selected row, but Lines 1562-1564 still render the old span details, so the inspector no longer matches the visible result set.Possible fix
+ useEffect(() => { + if (generations.length === 0) { + onSelectSpan(null); + return; + } + + if (!selectedSpan || !generations.some((g) => g.span_id === selectedSpan.spanId)) { + const first = generations[0]; + onSelectSpan({ runId: first.run_id, spanId: first.span_id }); + } + }, [generations, onSelectSpan, selectedSpan]);Also applies to: 1307-1310, 1480-1564
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx around lines 1290 - 1300, When pollFetcher updates generations (see pollFetcher handling that updates lastPollDataRef.current and setNewGenerationCount) ensure the inspector selection stays in sync by validating selectedSpan against the current generations array and clearing or updating it when the selected span is no longer present; specifically, after computing the new generations list (and where generations are replaced/merged in the poll/update paths) check if selectedSpan is null or its span_id exists in generations, and if not call setSelectedSpan(null) (or set to a sensible fallback like the first generation) so the inspector rendering (the code that reads selectedSpan to show details) always matches the visible table. Apply the same selection-validation logic to the other poll/update blocks noted (around the blocks corresponding to lines handling pollFetcher at 1307-1310 and the generation merge/render section around 1480-1564).
🧹 Nitpick comments (2)
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx (1)
132-134: Consider simplifying the nested spans.The current structure creates redundant nesting when
defaultModelis null, resulting in<span><span>-</span></span>.Suggested simplification
<TableCell to={path}> - <span>{prompt.defaultModel ?? <span>-</span>}</span> + {prompt.defaultModel ?? "-"} </TableCell>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx around lines 132 - 134, The TableCell currently nests spans redundantly when prompt.defaultModel is null; update the rendering inside the TableCell (where it references prompt.defaultModel) to render either the model string or a single '-' element without wrapping an extra <span>—e.g., use a single conditional that returns prompt.defaultModel or '-' (or a single span around the fallback) so TableCell contains only one span element instead of nested spans.apps/webapp/app/components/code/CodeBlock.tsx (1)
494-498: Simplify the redundant conditional.Both branches of the
isWrappedconditional apply the sameoverflow-autoclass, making the conditional unnecessary.♻️ Proposed simplification
const containerClasses = cn( "min-h-0 flex-1 px-3 py-3 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600", - !isWrapped && "overflow-auto", - isWrapped && "overflow-auto", + "overflow-auto", className );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/webapp/app/components/code/CodeBlock.tsx` around lines 494 - 498, The conditional in the containerClasses construction is redundant because both branches add "overflow-auto"; update the cn call in the CodeBlock component to remove the isWrapped checks and always include "overflow-auto" alongside the existing classes (referencing containerClasses, isWrapped, cn, and className) so the class list is simplified and the dead conditional is eliminated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/webapp/app/components/navigation/SideMenu.tsx`:
- Around line 468-481: The trailingIconClassName prop is being passed to
SideMenuItem here but SideMenuItem only applies that prop to trailingIcon (so
icon prop sizes are no-ops); update SideMenuItem (component SideMenuItem) to
accept a new iconClassName prop and apply it to the main icon element (where it
renders the icon prop), or alternatively change these callers in SideMenu.tsx to
pass the icon via the trailingIcon prop with trailingIconClassName — pick one
approach and implement it consistently so the AI icon sizes
(AIPromptsIcon/AIMetricsIcon) actually receive the intended class.
In `@apps/webapp/app/components/primitives/Resizable.tsx`:
- Around line 28-30: The onMouseDown handler in Resizable.tsx currently calls
e.preventDefault(), which prevents the separator from receiving focus; either
remove the e.preventDefault() call so clicks can focus the resizer, or if you
must keep preventing default behavior, immediately call (e.currentTarget as
HTMLElement).focus() after preventDefault to explicitly restore focus to the
separator (update the onMouseDown arrow function in the Resizable component
accordingly).
In `@apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsx`:
- Around line 3-10: The formatSpanDuration function can produce rollovers like
"1m 60s" because seconds are computed after toFixed rounding; change it to round
the total milliseconds (or total seconds) once first, then compute minutes and
seconds from that integer value so seconds never reach 60; update the
implementation in SpanHorizontalTimeline.tsx (function formatSpanDuration) to:
compute roundedMs = Math.round(nanoseconds / 1_000_000) (or roundedSeconds =
Math.round(nanoseconds / 1_000_000 / 1000) for second-granularity), then derive
mins = Math.floor(roundedMs / 60000) and secs = Math.floor((roundedMs % 60000) /
1000) (or use roundedSeconds % 60) and format accordingly; also extract/export
this helper so other components (span route) reuse the corrected formatter.
In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx:
- Around line 1963-2008: The version row is a non-focusable div; replace it with
a semantic, keyboard-focusable control (e.g., change the outer <div key={v.id}
...> to a <button type="button"> or a role="radio" element) so keyboard users
can tab and activate with Enter/Space, and keep the existing onClick={() =>
onSelectVersion(v.version)} and className logic; ensure RadioButtonCircle
receives the selected state (isSelected) and add appropriate ARIA
(aria-checked/aria-pressed or role="radio"/aria-checked) and tabindex handling
for accessibility, and make sure you do not create nested interactive controls
(adjust Badge/DateTime if they are interactive).
---
Outside diff comments:
In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx:
- Around line 1290-1300: When pollFetcher updates generations (see pollFetcher
handling that updates lastPollDataRef.current and setNewGenerationCount) ensure
the inspector selection stays in sync by validating selectedSpan against the
current generations array and clearing or updating it when the selected span is
no longer present; specifically, after computing the new generations list (and
where generations are replaced/merged in the poll/update paths) check if
selectedSpan is null or its span_id exists in generations, and if not call
setSelectedSpan(null) (or set to a sensible fallback like the first generation)
so the inspector rendering (the code that reads selectedSpan to show details)
always matches the visible table. Apply the same selection-validation logic to
the other poll/update blocks noted (around the blocks corresponding to lines
handling pollFetcher at 1307-1310 and the generation merge/render section around
1480-1564).
---
Nitpick comments:
In `@apps/webapp/app/components/code/CodeBlock.tsx`:
- Around line 494-498: The conditional in the containerClasses construction is
redundant because both branches add "overflow-auto"; update the cn call in the
CodeBlock component to remove the isWrapped checks and always include
"overflow-auto" alongside the existing classes (referencing containerClasses,
isWrapped, cn, and className) so the class list is simplified and the dead
conditional is eliminated.
In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx:
- Around line 132-134: The TableCell currently nests spans redundantly when
prompt.defaultModel is null; update the rendering inside the TableCell (where it
references prompt.defaultModel) to render either the model string or a single
'-' element without wrapping an extra <span>—e.g., use a single conditional that
returns prompt.defaultModel or '-' (or a single span around the fallback) so
TableCell contains only one span element instead of nested spans.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: b3d023a3-e014-4ac3-88db-33015ca92d89
📒 Files selected for processing (19)
apps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/tailwind.config.js
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: sdk-compat / Bun Runtime
- GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
- GitHub Check: sdk-compat / Deno Runtime
- GitHub Check: typecheck / typecheck
- GitHub Check: sdk-compat / Cloudflare Workers
- GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
**/*.{ts,tsx}: For apps and internal packages (apps/*,internal-packages/*), usepnpm run typecheck --filter <package>for verification, never usebuildas it proves almost nothing about correctness
Use testcontainers helpers (redisTest,postgresTest,containerTestfrom@internal/testcontainers) for integration tests with Redis and PostgreSQL instead of mocking
When writing Trigger.dev tasks, always import from@trigger.dev/sdk- never use@trigger.dev/sdk/v3or deprecatedclient.defineJob
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
**/*.{ts,tsx,js,jsx}: Use pnpm for package management in this monorepo (version 10.23.0) with Turborepo for orchestration - run commands from root withpnpm run
Add crumbs as you write code for debug tracing using//@Crumbscomments or `// `#region` `@crumbsblocks - they stay on the branch throughout development and are stripped viaagentcrumbs stripbefore merge
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/tailwind.config.jsapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier before committing
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/tailwind.config.jsapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
apps/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
When modifying only server components (
apps/webapp/,apps/supervisor/, etc.) with no package changes, add a.server-changes/file instead of a changeset
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/tailwind.config.jsapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
apps/webapp/app/**/*.{ts,tsx,server.ts}
📄 CodeRabbit inference engine (apps/webapp/CLAUDE.md)
Access environment variables via
envexport fromapp/env.server.ts. Never useprocess.envdirectly
Files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
🧠 Learnings (33)
📚 Learning: 2026-01-28T16:57:47.620Z
Learnt from: samejr
Repo: triggerdotdev/trigger.dev PR: 2964
File: apps/webapp/app/components/AskAI.tsx:121-141
Timestamp: 2026-01-28T16:57:47.620Z
Learning: In the trigger.dev webapp codebase, the Button component (apps/webapp/app/components/primitives/Buttons) does not spread unknown props to the underlying <button> element—it only passes specific props (type, disabled, onClick, name, value, ref, form, autoFocus). When using Radix UI's TooltipTrigger with asChild, a span wrapper around the Button is necessary to receive Radix props (aria-describedby, onPointerEnter, onPointerLeave, data-state) while the Button handles its own behavior. Directly making the Button the child of TooltipTrigger with asChild will break accessibility and tooltip functionality.
Applied to files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2026-02-11T16:37:32.429Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/components/primitives/charts/Card.tsx:26-30
Timestamp: 2026-02-11T16:37:32.429Z
Learning: In projects using react-grid-layout, avoid relying on drag-handle class to imply draggability. Ensure drag-handle elements only affect dragging when the parent grid item is configured draggable in the layout; conditionally apply cursor styles based on the draggable prop. This improves correctness and accessibility.
Applied to files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2026-03-22T13:26:12.060Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/code/TextEditor.tsx:81-86
Timestamp: 2026-03-22T13:26:12.060Z
Learning: In the triggerdotdev/trigger.dev codebase, do not flag `navigator.clipboard.writeText(...)` calls for `missing-await`/`unhandled-promise` issues. These clipboard writes are intentionally invoked without `await` and without `catch` handlers across the project; keep that behavior consistent when reviewing TypeScript/TSX files (e.g., usages like in `apps/webapp/app/components/code/TextEditor.tsx`).
Applied to files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2026-03-22T19:24:14.403Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3187
File: apps/webapp/app/v3/services/alerts/deliverErrorGroupAlert.server.ts:200-204
Timestamp: 2026-03-22T19:24:14.403Z
Learning: In the triggerdotdev/trigger.dev codebase, webhook URLs are not expected to contain embedded credentials/secrets (e.g., fields like `ProjectAlertWebhookProperties` should only hold credential-free webhook endpoints). During code review, if you see logging or inclusion of raw webhook URLs in error messages, do not automatically treat it as a credential-leak/secrets-in-logs issue by default—first verify the URL does not contain embedded credentials (for example, no username/password in the URL, no obvious secret/token query params or fragments). If the URL is credential-free per this project’s conventions, allow the logging.
Applied to files:
apps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2026-03-22T13:32:47.004Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/metrics/ProvidersFilter.tsx:74-96
Timestamp: 2026-03-22T13:32:47.004Z
Learning: In the triggerdotdev/trigger.dev codebase, `FilterMenuProvider` (in `apps/webapp/app/components/runs/v3/SharedFilters.tsx`) wraps Ariakit's `ComboboxProvider` and exposes `(search, setSearch)` as render props. Filter components like `ProvidersFilter`, `OperationsFilter`, `PromptsFilter`, `ModelsFilter`, and `QueuesFilter` all use this pattern: `searchValue` (from the render prop) is passed into the dropdown child and used in a `useMemo` to filter options. Because Ariakit's ComboboxProvider re-renders the render prop on every keystroke, `searchValue` is reactive and the filtered list updates correctly. Do not flag these patterns as broken/unconnected search state — the wiring is intentional and correct.
Applied to files:
apps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2026-03-22T13:32:40.255Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/metrics/PromptsFilter.tsx:74-98
Timestamp: 2026-03-22T13:32:40.255Z
Learning: In this repo’s filter components under apps/webapp/app/components/metrics/ (e.g., PromptsFilter, ModelsFilter, QueuesFilter), the search wiring intentionally uses a FilterMenuProvider render-prop pattern that wraps Ariakit’s ComboboxProvider. The render-prop `(search, setSearch)` is the live combobox search state, and the `searchValue` passed down to the inner `*Dropdown` component is designed to be updated on every keystroke. Do not raise review findings like “unconnected search state” or “broken filtering” for these components; the state propagation is correct by design and consistent with the other filter components in this directory.
Applied to files:
apps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/metrics/ModelsFilter.tsx
📚 Learning: 2026-03-22T13:32:43.005Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/metrics/OperationsFilter.tsx:85-110
Timestamp: 2026-03-22T13:32:43.005Z
Learning: In triggerdotdev/trigger.dev, the shared `FilterMenuProvider` (from `~/components/runs/v3/SharedFilters`) manages Ariakit `ComboboxProvider` state internally and exposes the current `search` value and `setSearch` via render props `(search, setSearch) => …`. For filter components (e.g., `OperationsFilter`, `ModelsFilter`, `QueuesFilter`, `ProvidersFilter`), treat the render-prop tuple and their use of `searchValue={search}` and `clearSearchValue={() => setSearch("")}` as the correct wiring. Do not raise a review finding about missing/broken connection between the ComboBox input and the search state—if the component follows this provider/render-prop pattern and the `filtered` `useMemo` dependencies are reactive, the state synchronization is expected to be handled by Ariakit through the provider.
Applied to files:
apps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `trigger.dev/sdk/v3` for all imports in Trigger.dev tasks
Applied to files:
apps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger.config.ts : Configure OpenTelemetry instrumentations and exporters in trigger.config.ts for enhanced logging
Applied to files:
apps/webapp/app/components/metrics/ProvidersFilter.tsx
📚 Learning: 2026-03-24T10:42:43.111Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3255
File: apps/webapp/app/routes/api.v1.runs.$runId.spans.$spanId.ts:100-100
Timestamp: 2026-03-24T10:42:43.111Z
Learning: In `apps/webapp/app/routes/api.v1.runs.$runId.spans.$spanId.ts` (and related span-handling code in trigger.dev), `span.entity` is a required (non-optional) field on the `SpanDetail` type and is always present. Do not flag `span.entity.type` as a potential null pointer / suggest optional chaining (`span.entity?.type`) in this context.
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to apps/webapp/app/v3/**/*.{ts,tsx} : In the webapp v3 directory, only modify V2 code paths when encountering V1/V2 branching in services - all new work uses Run Engine 2.0 (`internal/run-engine`) and redis-worker, not legacy V1 engine code
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `tasks.trigger()` with type-only imports to trigger tasks from backend code without importing the task implementation
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use the `task()` function from `trigger.dev/sdk/v3` to define tasks with id and run properties
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2026-03-23T06:24:14.566Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-03-23T06:24:14.566Z
Learning: Applies to **/*.{ts,tsx} : When writing Trigger.dev tasks, always import from `trigger.dev/sdk` - never use `trigger.dev/sdk/v3` or deprecated `client.defineJob`
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/BlankStatePanels.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use lifecycle functions (init, cleanup, onStart, onSuccess, onFailure, handleError) for task event handling
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use logger methods (debug, log, info, warn, error) from `trigger.dev/sdk/v3` for structured logging in tasks
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schedules.task()` for scheduled/cron tasks instead of regular `task()`
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `schemaTask()` from `trigger.dev/sdk/v3` with Zod schema for payload validation
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Use `yourTask.trigger()` to trigger a task from inside another task with specified payload
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Applies to **/trigger/**/*.{ts,tsx,js,jsx} : Export tasks with unique IDs within the project to enable proper task discovery and execution
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsx
📚 Learning: 2026-03-22T13:32:44.229Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/metrics/ProvidersFilter.tsx:74-96
Timestamp: 2026-03-22T13:32:44.229Z
Learning: When reviewing components under `apps/webapp/app/components/runs/v3/`, avoid flagging “broken/unconnected search state” in filters that use `FilterMenuProvider` wrapping Ariakit’s `ComboboxProvider` and expose `(search, setSearch)` (render props). In this intentional pattern, the `searchValue` render-prop value should be treated as reactive (it re-renders on every keystroke), passed into the dropdown child, and used in `useMemo` to filter options. Do not require additional wiring beyond this established render-prop/ComboboxProvider integration.
Applied to files:
apps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2026-02-03T18:27:40.429Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx:553-555
Timestamp: 2026-02-03T18:27:40.429Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx, the menu buttons (e.g., Edit with PencilSquareIcon) in the TableCellMenu are intentionally icon-only with no text labels as a compact UI pattern. This is a deliberate design choice for this route; preserve the icon-only behavior for consistency in this file.
Applied to files:
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2026-02-11T16:50:14.167Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dashboards.$dashboardId.widgets.tsx:126-131
Timestamp: 2026-02-11T16:50:14.167Z
Learning: In apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dashboards.$dashboardId.widgets.tsx, MetricsDashboard entities are intentionally scoped to the organization level, not the project level. The dashboard lookup should filter by organizationId only (not projectId), allowing dashboards to be accessed across projects within the same organization. The optional projectId field on MetricsDashboard serves other purposes and should not be used as an authorization constraint.
Applied to files:
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2025-11-27T16:26:58.661Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/webapp.mdc:0-0
Timestamp: 2025-11-27T16:26:58.661Z
Learning: Applies to apps/webapp/**/*.{ts,tsx} : Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Applied to files:
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.
Applied to files:
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2026-03-21T21:23:35.117Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/runs/v3/ai/extractAISummarySpanData.ts:149-150
Timestamp: 2026-03-21T21:23:35.117Z
Learning: In `apps/webapp/app/components/runs/v3/ai/extractAISummarySpanData.ts` (and related AI span extraction files in `apps/webapp/app/components/runs/v3/ai/`), manual JSON.parse with typeof guards and type assertions is intentional. These functions are on the hot path for span rendering, so Zod validation is deliberately avoided for performance reasons. Do not suggest replacing manual JSON parsing with Zod schemas in these files.
Applied to files:
apps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Use `useRun`, `useRealtimeRun` and other SWR/realtime hooks from `trigger.dev/react-hooks` for data fetching
Applied to files:
apps/webapp/app/components/runs/v3/ai/AISpanDetails.tsx
📚 Learning: 2026-02-03T18:27:49.039Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx:553-555
Timestamp: 2026-02-03T18:27:49.039Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx, the menu buttons (like the Edit button with PencilSquareIcon) intentionally have no text labels - only icons are shown in the TableCellMenu. This is a deliberate UI design pattern for compact icon-only menu items.
Applied to files:
apps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/navigation/SideMenu.tsx
📚 Learning: 2025-11-27T16:27:35.304Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: .cursor/rules/writing-tasks.mdc:0-0
Timestamp: 2025-11-27T16:27:35.304Z
Learning: Run `npx trigger.devlatest init` to initialize a Trigger.dev project
Applied to files:
apps/webapp/app/components/BlankStatePanels.tsx
📚 Learning: 2026-03-22T13:45:36.346Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/navigation/SideMenu.tsx:460-489
Timestamp: 2026-03-22T13:45:36.346Z
Learning: In triggerdotdev/trigger.dev, sidebar navigation items (SideMenu.tsx) are intentionally NOT gated behind feature-flag or permission checks at the nav level. Authorization is enforced at the route/loader level instead. Hiding nav items based on access checks is considered confusing UX. This applies to items like "AI Metrics" (v3BuiltInDashboardPath) and other dashboard links — they are always rendered in the sidebar regardless of hasQueryAccess or similar flags.
Applied to files:
apps/webapp/app/components/navigation/SideMenu.tsx
📚 Learning: 2026-03-22T13:32:43.689Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/metrics/PromptsFilter.tsx:74-98
Timestamp: 2026-03-22T13:32:43.689Z
Learning: In triggerdotdev/trigger.dev, filter components (e.g. PromptsFilter, ModelsFilter, QueuesFilter in apps/webapp/app/components/metrics/) use a `FilterMenuProvider` render-prop pattern that wraps Ariakit's ComboboxProvider. The render props `(search, setSearch)` represent live combobox search state; `searchValue` passed to the inner `*Dropdown` component is always up-to-date on each keystroke. Do not flag these components for "unconnected search state" or "broken filtering" — the wiring is correct by design and consistent across all filter components.
Applied to files:
apps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
📚 Learning: 2026-01-28T14:15:09.778Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2953
File: apps/webapp/app/components/runs/v3/SharedFilters.tsx:441-452
Timestamp: 2026-01-28T14:15:09.778Z
Learning: In apps/webapp/app/components/runs/v3/SharedFilters.tsx, enforce the maxPeriodDays limit based only on the from date (fromValue) using dateRangeToDays(fromValue) to reflect data retention limits. The to date should be ignored for retention checks. Ensure any retention-window logic or validations rely solely on the fromValue, and update related comments/tests if needed.
Applied to files:
apps/webapp/app/components/runs/v3/SharedFilters.tsx
📚 Learning: 2026-03-22T13:32:46.525Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/metrics/OperationsFilter.tsx:85-110
Timestamp: 2026-03-22T13:32:46.525Z
Learning: In triggerdotdev/trigger.dev, `FilterMenuProvider` (from `~/components/runs/v3/SharedFilters`) wraps Ariakit's `ComboboxProvider` and exposes the current search string and setter via render props `(search, setSearch) => …`. Components like `OperationsFilter`, `ModelsFilter`, `QueuesFilter`, and `ProvidersFilter` all use this pattern: they pass `searchValue={search}` and `clearSearchValue={() => setSearch("")}` into their inner dropdown component, and the `filtered` useMemo is correctly reactive. Do not flag this as a missing/broken wiring between the ComboBox input and the search state — the state is managed by Ariakit's provider and surfaced through the render-prop tuple.
Applied to files:
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
🔇 Additional comments (20)
apps/webapp/app/components/primitives/TextArea.tsx (1)
11-11: Nice cleanup on the textarea class list.Removing the duplicated focus utility keeps styles predictable without changing behavior.
apps/webapp/app/components/metrics/ProvidersFilter.tsx (1)
16-16: Shortcut remap looks good.The
Providerstrigger shortcut update is clean and safely scoped to UI behavior.apps/webapp/app/components/metrics/ModelsFilter.tsx (1)
19-19: Shortcut update is solid.The key change is narrowly scoped and aligns with the UI shortcut cleanup in this PR.
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx (4)
85-89: LGTM!The documentation link follows the established pattern for adding page accessories with a docs button. Clean implementation.
118-131: LGTM!Good simplification of the table cell markup. The description truncation with tooltip for long text is a nice UX touch.
136-147: Good use of semantic color tokens.Switching from hardcoded Tailwind colors (
bg-amber-400/bg-green-500) to semantic tokens (bg-warning/bg-success) improves maintainability and ensures consistency with the design system.
174-185: LGTM!The sparkline component is clean and handles the empty/zero data case appropriately.
apps/webapp/app/components/primitives/Resizable.tsx (1)
7-16: LGTM on the slimmerPanelGroupwrapper.Keeping
snapshotinside...propspreserves the existingsnapshot={...}callers while simplifying this wrapper.apps/webapp/app/components/runs/v3/SpanTitle.tsx (2)
2-2: LGTM!The type-only import for
TaskEventStyleis correct since it's only used as a type annotation, improving tree-shaking.
22-22: LGTM!Adding
text-text-brightimproves visual consistency for span messages.apps/webapp/app/components/layout/AppLayout.tsx (1)
23-35: LGTM!The
PageContainerupdate follows the same pattern as other container components in this file (AppContainer,PageBody,MainCenteredContainer), maintaining API consistency.apps/webapp/app/assets/icons/AIPromptsIcon.tsx (1)
1-10: LGTM!The icon component follows established patterns with
fill="currentColor"for Tailwind color utility support and an optionalclassNameprop for styling flexibility.apps/webapp/tailwind.config.js (1)
178-179: LGTM!The new
aiPromptsandaiMetricscolor tokens follow the established pattern for semantic icon colors in this config (e.g.,tasks,runs,batches).Also applies to: 263-264
apps/webapp/app/assets/icons/AIMetricsIcon.tsx (1)
1-16: LGTM!The icon component is consistent with
AIPromptsIconand follows established patterns.apps/webapp/app/components/runs/v3/SharedFilters.tsx (2)
379-388: LGTM!The shortcut integration correctly prevents default behavior and stops propagation before programmatically clicking the trigger. Using a ref to trigger the click is a valid pattern for opening dropdowns via keyboard shortcuts.
403-433: LGTM!The Ariakit tooltip integration is well-structured: the
TooltipAnchorwraps theSelectusing therenderprop pattern, and theTooltipis conditionally rendered only when a shortcut is provided. Thez-40ensures proper stacking.apps/webapp/app/components/code/CodeBlock.tsx (1)
268-271: LGTM!Converting to flex column layout with
overflow-hiddenon the outer container provides better control over child overflow behavior, which is necessary for theflex-1andmin-h-0approach used by inner elements.apps/webapp/app/components/BlankStatePanels.tsx (2)
696-697: LGTM!Switching to
AIPromptsIconwith the newtext-aiPromptscolor token aligns with the PR's goal of consistent AI-related styling.
717-730: LGTM!Replacing the hardcoded
<pre>with the sharedCodeBlockcomponent improves consistency and leverages built-in features like copy functionality. TheshowLineNumbers={false}andshowOpenInModal={false}options are appropriate for this inline example context.apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx (1)
488-492: Nice compact metadata copy UX.Surfacing slug, friendly ID, and description copy actions from the title popover keeps the header clean while still making the common identifiers easy to grab.
Also applies to: 2017-2118
...pp.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
Show resolved
Hide resolved
…n-ui-improvements
99d079a to
a08ffac
Compare
...pp.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
Show resolved
Hide resolved
...es/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
🧹 Nitpick comments (1)
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx (1)
305-312: Consider extracting and sharingformatSpanDurationto avoid divergence.This file has its own
formatSpanDurationimplementation that differs from the one inSpanHorizontalTimeline.tsx. The route version still uses((ms % 60_000) / 1000).toFixed(0)which can produce"1m 60s"for edge cases likems = 119600.Since this function isn't used in the current render paths (the removed header row was the consumer), you could either:
- Remove this unused function, or
- Export the fixed version from
SpanHorizontalTimeline.tsxand reuse it here if needed elsewhere.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/webapp/app/routes/resources.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx around lines 305 - 312, The local formatSpanDuration implementation can produce edge-case outputs like "1m 60s" and diverges from the canonical version in SpanHorizontalTimeline.tsx; either remove this unused formatSpanDuration from route.tsx, or replace it by importing the fixed, exported formatSpanDuration from SpanHorizontalTimeline.tsx so both locations share one implementation (update exports in SpanHorizontalTimeline.tsx if needed and change the route to import and use that exported function).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In
`@apps/webapp/app/routes/resources.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx:
- Around line 305-312: The local formatSpanDuration implementation can produce
edge-case outputs like "1m 60s" and diverges from the canonical version in
SpanHorizontalTimeline.tsx; either remove this unused formatSpanDuration from
route.tsx, or replace it by importing the fixed, exported formatSpanDuration
from SpanHorizontalTimeline.tsx so both locations share one implementation
(update exports in SpanHorizontalTimeline.tsx if needed and change the route to
import and use that exported function).
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 5ae95c53-6711-4e76-9a2f-47b80e99a110
📒 Files selected for processing (19)
apps/webapp/app/assets/icons/AIMetricsIcon.tsxapps/webapp/app/assets/icons/AIPromptsIcon.tsxapps/webapp/app/components/BlankStatePanels.tsxapps/webapp/app/components/code/CodeBlock.tsxapps/webapp/app/components/layout/AppLayout.tsxapps/webapp/app/components/metrics/ModelsFilter.tsxapps/webapp/app/components/metrics/ProvidersFilter.tsxapps/webapp/app/components/navigation/SideMenu.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/components/primitives/TextArea.tsxapps/webapp/app/components/runs/v3/PromptSpanDetails.tsxapps/webapp/app/components/runs/v3/SharedFilters.tsxapps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/runs/v3/SpanTitle.tsxapps/webapp/app/components/runs/v3/ai/AISpanDetails.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsxapps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsxapps/webapp/tailwind.config.js
✅ Files skipped from review due to trivial changes (7)
- apps/webapp/app/components/metrics/ProvidersFilter.tsx
- apps/webapp/app/components/primitives/TextArea.tsx
- apps/webapp/app/components/metrics/ModelsFilter.tsx
- apps/webapp/app/assets/icons/AIMetricsIcon.tsx
- apps/webapp/tailwind.config.js
- apps/webapp/app/components/code/CodeBlock.tsx
- apps/webapp/app/assets/icons/AIPromptsIcon.tsx
🚧 Files skipped from review as they are similar to previous changes (9)
- apps/webapp/app/components/runs/v3/PromptSpanDetails.tsx
- apps/webapp/app/components/runs/v3/SpanTitle.tsx
- apps/webapp/app/components/runs/v3/ai/AISpanDetails.tsx
- apps/webapp/app/components/layout/AppLayout.tsx
- apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts._index/route.tsx
- apps/webapp/app/components/BlankStatePanels.tsx
- apps/webapp/app/components/runs/v3/SharedFilters.tsx
- apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.prompts.$promptSlug/route.tsx
- apps/webapp/app/components/navigation/SideMenu.tsx
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
- GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
- GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
- GitHub Check: sdk-compat / Deno Runtime
- GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
- GitHub Check: typecheck / typecheck
- GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
- GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
- GitHub Check: sdk-compat / Cloudflare Workers
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
- GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
- GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
- GitHub Check: sdk-compat / Bun Runtime
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
**/*.{ts,tsx}: Use types over interfaces for TypeScript
Avoid using enums; prefer string unions or const objects instead
**/*.{ts,tsx}: For apps and internal packages (apps/*,internal-packages/*), usepnpm run typecheck --filter <package>for verification, never usebuildas it proves almost nothing about correctness
Use testcontainers helpers (redisTest,postgresTest,containerTestfrom@internal/testcontainers) for integration tests with Redis and PostgreSQL instead of mocking
When writing Trigger.dev tasks, always import from@trigger.dev/sdk- never use@trigger.dev/sdk/v3or deprecatedclient.defineJob
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
{packages/core,apps/webapp}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use zod for validation in packages/core and apps/webapp
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use function declarations instead of default exports
**/*.{ts,tsx,js,jsx}: Use pnpm for package management in this monorepo (version 10.23.0) with Turborepo for orchestration - run commands from root withpnpm run
Add crumbs as you write code for debug tracing using//@Crumbscomments or `// `#region` `@crumbsblocks - they stay on the branch throughout development and are stripped viaagentcrumbs stripbefore merge
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
apps/webapp/app/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
Access all environment variables through the
envexport ofenv.server.tsinstead of directly accessingprocess.envin the Trigger.dev webapp
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
apps/webapp/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)
apps/webapp/**/*.{ts,tsx}: When importing from@trigger.dev/corein the webapp, use subpath exports from the package.json instead of importing from the root path
Follow the Remix 2.1.0 and Express server conventions when updating the main trigger.dev webapp
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}
📄 CodeRabbit inference engine (AGENTS.md)
Format code using Prettier before committing
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
apps/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
When modifying only server components (
apps/webapp/,apps/supervisor/, etc.) with no package changes, add a.server-changes/file instead of a changeset
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
apps/webapp/app/**/*.{ts,tsx,server.ts}
📄 CodeRabbit inference engine (apps/webapp/CLAUDE.md)
Access environment variables via
envexport fromapp/env.server.ts. Never useprocess.envdirectly
Files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
🧠 Learnings (13)
📚 Learning: 2026-03-24T10:42:43.111Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3255
File: apps/webapp/app/routes/api.v1.runs.$runId.spans.$spanId.ts:100-100
Timestamp: 2026-03-24T10:42:43.111Z
Learning: In `apps/webapp/app/routes/api.v1.runs.$runId.spans.$spanId.ts` (and related span-handling code in trigger.dev), `span.entity` is a required (non-optional) field on the `SpanDetail` type and is always present. Do not flag `span.entity.type` as a potential null pointer / suggest optional chaining (`span.entity?.type`) in this context.
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-01-28T14:15:15.011Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2953
File: apps/webapp/app/components/runs/v3/SharedFilters.tsx:441-452
Timestamp: 2026-01-28T14:15:15.011Z
Learning: In apps/webapp/app/components/runs/v3/SharedFilters.tsx, the maxPeriodDays limit for date ranges should only check the from date (via dateRangeToDays(fromValue)) because it enforces data retention limits—how far back in history queries can reach. The to date is irrelevant for retention-based limits.
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsx
📚 Learning: 2026-03-22T13:51:25.797Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/presenters/v3/PromptPresenter.server.ts:100-141
Timestamp: 2026-03-22T13:51:25.797Z
Learning: In the triggerdotdev/trigger.dev codebase, the ClickHouse server is configured with UTC as its timezone. Therefore, `toStartOfHour(start_time)` (without an explicit timezone argument) in ClickHouse queries correctly returns UTC-formatted strings that align with JavaScript `toISOString()`-derived UTC bucket keys (e.g., in `apps/webapp/app/presenters/v3/PromptPresenter.server.ts`). Do not flag this as a timezone mismatch bug.
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsx
📚 Learning: 2026-03-22T13:51:25.797Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/presenters/v3/PromptPresenter.server.ts:100-141
Timestamp: 2026-03-22T13:51:25.797Z
Learning: In the triggerdotdev/trigger.dev codebase, the ClickHouse server is configured with UTC timezone. Therefore, `toStartOfHour(start_time)` (without an explicit timezone argument) in ClickHouse queries returns UTC-formatted strings, which correctly align with JavaScript `toISOString()`-derived UTC bucket keys. Do not flag this pattern as a timezone mismatch bug.
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsx
📚 Learning: 2026-02-11T16:37:32.429Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/components/primitives/charts/Card.tsx:26-30
Timestamp: 2026-02-11T16:37:32.429Z
Learning: In projects using react-grid-layout, avoid relying on drag-handle class to imply draggability. Ensure drag-handle elements only affect dragging when the parent grid item is configured draggable in the layout; conditionally apply cursor styles based on the draggable prop. This improves correctness and accessibility.
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-03-22T13:26:12.060Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/code/TextEditor.tsx:81-86
Timestamp: 2026-03-22T13:26:12.060Z
Learning: In the triggerdotdev/trigger.dev codebase, do not flag `navigator.clipboard.writeText(...)` calls for `missing-await`/`unhandled-promise` issues. These clipboard writes are intentionally invoked without `await` and without `catch` handlers across the project; keep that behavior consistent when reviewing TypeScript/TSX files (e.g., usages like in `apps/webapp/app/components/code/TextEditor.tsx`).
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-03-22T19:24:14.403Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3187
File: apps/webapp/app/v3/services/alerts/deliverErrorGroupAlert.server.ts:200-204
Timestamp: 2026-03-22T19:24:14.403Z
Learning: In the triggerdotdev/trigger.dev codebase, webhook URLs are not expected to contain embedded credentials/secrets (e.g., fields like `ProjectAlertWebhookProperties` should only hold credential-free webhook endpoints). During code review, if you see logging or inclusion of raw webhook URLs in error messages, do not automatically treat it as a credential-leak/secrets-in-logs issue by default—first verify the URL does not contain embedded credentials (for example, no username/password in the URL, no obvious secret/token query params or fragments). If the URL is credential-free per this project’s conventions, allow the logging.
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsxapps/webapp/app/components/primitives/Resizable.tsxapps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-03-22T13:32:44.229Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/metrics/ProvidersFilter.tsx:74-96
Timestamp: 2026-03-22T13:32:44.229Z
Learning: When reviewing components under `apps/webapp/app/components/runs/v3/`, avoid flagging “broken/unconnected search state” in filters that use `FilterMenuProvider` wrapping Ariakit’s `ComboboxProvider` and expose `(search, setSearch)` (render props). In this intentional pattern, the `searchValue` render-prop value should be treated as reactive (it re-renders on every keystroke), passed into the dropdown child, and used in `useMemo` to filter options. Do not require additional wiring beyond this established render-prop/ComboboxProvider integration.
Applied to files:
apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsx
📚 Learning: 2026-02-11T16:50:14.167Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 3019
File: apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dashboards.$dashboardId.widgets.tsx:126-131
Timestamp: 2026-02-11T16:50:14.167Z
Learning: In apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.dashboards.$dashboardId.widgets.tsx, MetricsDashboard entities are intentionally scoped to the organization level, not the project level. The dashboard lookup should filter by organizationId only (not projectId), allowing dashboards to be accessed across projects within the same organization. The optional projectId field on MetricsDashboard serves other purposes and should not be used as an authorization constraint.
Applied to files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2025-12-08T15:19:56.823Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2760
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx:278-281
Timestamp: 2025-12-08T15:19:56.823Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx, the tableState search parameter uses intentional double-encoding: the parameter value contains a URL-encoded URLSearchParams string, so decodeURIComponent(value("tableState") ?? "") is required to fully decode it before parsing with new URLSearchParams(). This pattern allows bundling multiple filter/pagination params as a single search parameter.
Applied to files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-03-21T21:23:35.117Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3244
File: apps/webapp/app/components/runs/v3/ai/extractAISummarySpanData.ts:149-150
Timestamp: 2026-03-21T21:23:35.117Z
Learning: In `apps/webapp/app/components/runs/v3/ai/extractAISummarySpanData.ts` (and related AI span extraction files in `apps/webapp/app/components/runs/v3/ai/`), manual JSON.parse with typeof guards and type assertions is intentional. These functions are on the hot path for span rendering, so Zod validation is deliberately avoided for performance reasons. Do not suggest replacing manual JSON parsing with Zod schemas in these files.
Applied to files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-03-13T13:43:06.471Z
Learnt from: ericallam
Repo: triggerdotdev/trigger.dev PR: 3213
File: apps/webapp/app/components/runs/v3/ai/extractAISpanData.ts:52-52
Timestamp: 2026-03-13T13:43:06.471Z
Learning: In the trigger.dev codebase (PR `#3213`), `extractAISpanData.ts` (`apps/webapp/app/components/runs/v3/ai/extractAISpanData.ts`) is a read-side UI helper that reads already-enriched `trigger.llm.*` span attributes for display. The actual LLM cost computation and gateway/OpenRouter cost fallback logic lives in `enrichCreatableEvents.server.ts` (`apps/webapp/app/v3/utils/enrichCreatableEvents.server.ts`) via `extractProviderCost()`. The `gatewayCost` parsed in `extractAISpanData` is for UI display purposes only, not for cost calculation.
Applied to files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
📚 Learning: 2026-02-03T18:27:40.429Z
Learnt from: 0ski
Repo: triggerdotdev/trigger.dev PR: 2994
File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx:553-555
Timestamp: 2026-02-03T18:27:40.429Z
Learning: In apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx, the menu buttons (e.g., Edit with PencilSquareIcon) in the TableCellMenu are intentionally icon-only with no text labels as a compact UI pattern. This is a deliberate design choice for this route; preserve the icon-only behavior for consistency in this file.
Applied to files:
apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx
🔇 Additional comments (6)
apps/webapp/app/components/primitives/Resizable.tsx (3)
28-30: Restore focus after preventing default to preserve keyboard accessibility.The
e.preventDefault()on mousedown prevents text selection during drag (good), but also prevents the handle from receiving focus on click. This breaks keyboard resizing until the user tabs back to the handle.♿ Suggested fix
const ResizableHandle = ({ withHandle = true, className, + onMouseDown, ...props }: React.ComponentProps<typeof PanelResizer> & { withHandle?: boolean; }) => ( <PanelResizer - onMouseDown={(e: React.MouseEvent) => { + onMouseDown={(e: React.MouseEvent<HTMLElement>) => { + onMouseDown?.(e); + if (e.defaultPrevented) return; + e.preventDefault(); + e.currentTarget.focus(); }}
7-16: LGTM!The refactored
ResizablePanelGroupcleanly preserves functionality. Thesnapshotprop correctly flows through via the spread, and theautosaveStrategycomputation based onautosaveIdis appropriately placed before the spread to allow explicit overrides when needed.
51-57: LGTM!The visual refinements are well-implemented:
pointer-events-noneon the overlay divs correctly prevents interaction interference, and the opacity transition approach provides smoother UX than the previous display toggling.apps/webapp/app/components/runs/v3/SpanHorizontalTimeline.tsx (1)
1-54: LGTM!The component is well-structured with clear separation between the duration formatting logic and the timeline rendering. The nanosecond-to-millisecond conversion is handled correctly, and the conditional rendering based on
durationavailability is clean.apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.spans.$spanParam/route.tsx (2)
1413-1452: Clean integration of timing props across AI span entity types.The consistent pattern of passing
startTimeanddurationto the detail components, combined with wrappingai-tool-callandai-embedtypes withSpanHorizontalTimeline, provides a unified timing display across all AI-related spans. The scrollable container wrapper is appropriate for these detail views.
1426-1443: No changes needed. Thespan.durationfield is a requirednumberproperty on theSpanDetailtype, not optional. Passing it directly toSpanHorizontalTimeline(which acceptsduration: number | null) is type-safe. The defensiveduration ?? nullpattern used inAISpanDetailsandPromptSpanDetailsis necessary in those components because they receive optional duration parameters from their callers, not becausespan.durationitself could be undefined.> Likely an incorrect or invalid review comment.
Lots of UI improvements to the Prompts pages:
New side menu icons
Compact horizontal start finish times so scanning generations list is consistent
Tidied up the metrics view
Copiable metadata
Cleaner versions list
Overall consistency improvements, shortcut keys and UI behaviours improvements