Skip to content

Conversation

@ericallam
Copy link
Member

Add theme switching capability with light, dark, and system modes:

  • Enable Tailwind CSS dark mode with class strategy
  • Add CSS variables for theme-aware semantic colors
  • Create ThemeProvider context for managing theme state
  • Add ThemeToggle component in side menu and account settings
  • Persist theme preference to user dashboard preferences
  • Include ThemeScript to prevent flash of wrong theme on load

https://claude.ai/code/session_01VDVgh75Xa4LA9YH9aFLnjB

@changeset-bot
Copy link

changeset-bot bot commented Jan 30, 2026

⚠️ No Changeset found

Latest commit: b5a1402

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 30, 2026

Walkthrough

Adds a theme system and UI across the webapp: introduces ThemeProvider, useTheme, and ThemeScript; adds ThemeToggle and ThemeToggleButtons UI components; persists preference locally and via a new Remix action route that updates dashboard preferences (new ThemePreference type and updateThemePreference function). Integrates ThemeProvider/ThemeScript in root rendering and ErrorBoundary, surfaces ThemeToggle in the sidebar and account settings, and updates Tailwind config and CSS to use theme-aware CSS variables. Additionally, many components’ classNames were updated to new theme token utilities (hover/grid/tertiary) for consistent styling.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description covers the key aspects of the changes but lacks some template sections. Missing are: issue reference (Closes #), checklist completion, testing steps, and changelog section. Complete the PR description by following the template: add issue reference, mark checklist items, describe testing steps performed, and provide a structured changelog entry.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main feature being added: light mode support to the dashboard. It accurately reflects the primary objective of the PR.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/slack-add-light-mode-dashboard-2ETGS

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vibe-kanban-cloud
Copy link

Review Complete

Your review story is ready!

View Story

Comment !reviewfast on this PR to re-generate the story.

Add theme switching capability with light, dark, and system modes:
- Enable Tailwind CSS dark mode with class strategy
- Add CSS variables for theme-aware semantic colors
- Create ThemeProvider context for managing theme state
- Add ThemeToggle component in side menu and account settings
- Persist theme preference to user dashboard preferences
- Include ThemeScript to prevent flash of wrong theme on load

Slack thread: https://triggerdotdev.slack.com/archives/C04CR1HUWBV/p1769765128711039

https://claude.ai/code/session_01VDVgh75Xa4LA9YH9aFLnjB
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/webapp/app/components/primitives/ThemeProvider.tsx`:
- Around line 107-121: ThemeScript currently only adds a theme class which can
leave both 'dark' and 'light' present; update the injected script (in
ThemeScript using the initialPreference prop) to first remove any existing theme
classes from document.documentElement.classList (e.g.,
classList.remove('light','dark')) before computing/adding the chosen theme so
you never end up with both classes during initial render/hydration.

In `@apps/webapp/app/components/primitives/ThemeToggle.tsx`:
- Around line 16-19: Replace the interface ThemeToggleProps with a type alias:
change the declaration of ThemeToggleProps from an interface to a type (e.g.,
type ThemeToggleProps = { className?: string; isCollapsed?: boolean; }) and
update any references (ThemeToggleProps) accordingly so the props shape uses a
Type alias instead of an interface in ThemeToggle.tsx.
🧹 Nitpick comments (4)
apps/webapp/app/tailwind.css (1)

221-221: Consider using theme variables for scrollbar colors.

The scrollbar thumb uses hardcoded charcoal-400 and charcoal-600 with a dark: variant, while the rest of the file uses CSS variable-based theme tokens. For consistency, consider mapping these to theme variables or using the semantic tokens defined above.

♻️ Suggested refactor using theme-aware colors
-    `@apply` scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-400 dark:scrollbar-thumb-charcoal-600;
+    `@apply` scrollbar-thin scrollbar-track-transparent scrollbar-thumb-text-dimmed;

This would use the --color-text-dimmed variable which already adapts to light/dark mode, eliminating the need for the dark: variant.

apps/webapp/app/components/primitives/ThemeProvider.tsx (1)

14-40: Use type aliases instead of interfaces here.
This file defines two interfaces; the guideline prefers type for TS.

♻️ Suggested refactor
-interface ThemeContextValue {
-  theme: Theme;
-  themePreference: ThemePreference;
-  setThemePreference: (preference: ThemePreference) => void;
-}
+type ThemeContextValue = {
+  theme: Theme;
+  themePreference: ThemePreference;
+  setThemePreference: (preference: ThemePreference) => void;
+};
@@
-interface ThemeProviderProps {
-  children: ReactNode;
-  initialPreference?: ThemePreference;
-  isLoggedIn?: boolean;
-}
+type ThemeProviderProps = {
+  children: ReactNode;
+  initialPreference?: ThemePreference;
+  isLoggedIn?: boolean;
+};
As per coding guidelines, `**/*.{ts,tsx}`: Use types over interfaces for TypeScript.
apps/webapp/app/components/primitives/ThemeToggle.tsx (2)

25-26: Avoid index-based fallback for the current option.
Using themeOptions[1] is brittle if the array is reordered. Prefer an explicit value lookup for the default (e.g., "dark").

♻️ Example tweak
-  const currentOption = themeOptions.find((opt) => opt.value === themePreference) ?? themeOptions[1];
+  const currentOption =
+    themeOptions.find((opt) => opt.value === themePreference) ??
+    themeOptions.find((opt) => opt.value === "dark") ??
+    themeOptions[0];

31-37: Add accessible names (and pressed state) for icon‑only theme controls.
The trigger button is icon‑only, and the compact buttons lose text on small screens; add aria-label (and aria-pressed) to make the controls screen‑reader friendly. If your Button component doesn’t forward aria-* props to the underlying <button>, you’ll need to add that support there.

♿ Suggested accessibility improvements
             <Button
               variant="minimal/small"
               className={cn("aspect-square h-7 p-1", className)}
               LeadingIcon={CurrentIcon}
+              aria-label={`Theme: ${currentOption.label}`}
             />
...
          <button
             key={option.value}
             type="button"
             onClick={() => setThemePreference(option.value)}
             className={cn(
               "flex items-center gap-1.5 rounded px-2 py-1 text-xs transition-colors",
               isSelected
                 ? "bg-background-bright text-text-bright shadow-sm"
                 : "text-text-dimmed hover:text-text-bright"
             )}
             title={option.label}
+            aria-label={option.label}
+            aria-pressed={isSelected}
          >

Also applies to: 81-95

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e6861f4 and 1d63f2d.

📒 Files selected for processing (9)
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
  • apps/webapp/app/components/primitives/ThemeToggle.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/tailwind.css
  • apps/webapp/tailwind.config.js
🧰 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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/components/primitives/ThemeToggle.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.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/ThemeToggle.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/components/primitives/ThemeToggle.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
  • apps/webapp/tailwind.config.js
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/components/primitives/ThemeToggle.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in 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

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/components/primitives/ThemeToggle.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.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/ThemeToggle.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
  • apps/webapp/tailwind.config.js
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/dashboardPreferences.server.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • apps/webapp/app/services/dashboardPreferences.server.ts
🧠 Learnings (1)
📚 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/root.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
🧬 Code graph analysis (5)
apps/webapp/app/components/primitives/ThemeToggle.tsx (7)
apps/webapp/app/services/dashboardPreferences.server.ts (2)
  • ThemePreference (13-13)
  • ThemePreference (14-14)
apps/webapp/app/components/primitives/ThemeProvider.tsx (1)
  • useTheme (99-105)
apps/webapp/app/components/primitives/Popover.tsx (4)
  • Popover (265-265)
  • PopoverTrigger (272-272)
  • PopoverContent (267-267)
  • PopoverMenuItem (269-269)
apps/webapp/app/components/primitives/Tooltip.tsx (1)
  • SimpleTooltip (141-141)
apps/webapp/app/components/primitives/Buttons.tsx (1)
  • Button (296-329)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/Icon.tsx (1)
  • Icon (12-37)
apps/webapp/app/services/dashboardPreferences.server.ts (1)
apps/webapp/app/services/session.server.ts (1)
  • UserFromSession (37-37)
apps/webapp/app/routes/resources.preferences.theme.tsx (3)
apps/webapp/app/services/dashboardPreferences.server.ts (3)
  • ThemePreference (13-13)
  • ThemePreference (14-14)
  • updateThemePreference (159-188)
apps/webapp/app/services/session.server.ts (1)
  • requireUser (39-62)
packages/core/src/v3/apps/http.ts (1)
  • json (65-75)
apps/webapp/app/components/navigation/SideMenu.tsx (3)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/ThemeToggle.tsx (1)
  • ThemeToggle (21-66)
apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx (1)
  • HelpAndFeedback (32-254)
apps/webapp/app/components/primitives/ThemeProvider.tsx (1)
apps/webapp/app/services/dashboardPreferences.server.ts (2)
  • ThemePreference (13-13)
  • ThemePreference (14-14)
🪛 ast-grep (0.40.5)
apps/webapp/app/components/primitives/ThemeProvider.tsx

[warning] 120-120: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.3.13)
apps/webapp/app/tailwind.css

[error] 177-177: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 180-180: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 183-183: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 192-192: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 195-195: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 198-198: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 201-201: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 206-206: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 209-209: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 221-221: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)

apps/webapp/app/components/primitives/ThemeProvider.tsx

[error] 121-121: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🔇 Additional comments (22)
apps/webapp/app/tailwind.css (3)

36-76: Well-structured theme variable system.

The CSS variable approach with :root for light mode defaults and .dark class overrides aligns well with Tailwind's darkMode: "class" strategy. The semantic color naming (text-dimmed/bright, background-dimmed/bright, grid-dimmed/bright) provides good abstraction for theming.


143-146: Streamdown shadcn variable overrides look correct.

The shadcn CSS variables (--muted, --muted-foreground, --foreground, --border) are properly defined for light mode in .streamdown-container and overridden for dark mode in .dark .streamdown-container. This ensures the Streamdown component renders correctly in both themes.

Also applies to: 232-236


177-221: Static analysis hints are false positives.

The Biome errors about "Tailwind-specific syntax is disabled" on the @apply directives are false positives. These are valid Tailwind CSS directives that will be processed correctly by the Tailwind compiler. To suppress these warnings, you could configure Biome to enable tailwindDirectives in the CSS parser options, but this is not a code issue.

apps/webapp/app/services/dashboardPreferences.server.ts (3)

13-15: Theme preference schema/type looks solid.
Centralizing the preference in a zod schema + type alias makes reuse consistent across the app.


16-27: Optional theme field is backward‑compatible.
Adding theme as optional preserves existing preference payloads.


159-187: Update flow is safe and scoped.
Impersonation guard + no‑op check keep writes minimal and safe.

apps/webapp/tailwind.config.js (3)

136-165: Light‑mode semantic tokens are a good foundation.
Clear separation of light values will help future token wiring.


191-191: darkMode: "class" aligns with ThemeProvider strategy.


231-240: CSS‑variable color mapping is well‑aligned with theming.

apps/webapp/app/routes/account._index/route.tsx (2)

25-25: Theme toggle import is appropriate for the new Appearance section.


200-207: Appearance block integrates cleanly.
Nice, compact placement of the theme selector with label + hint.

apps/webapp/app/components/navigation/SideMenu.tsx (2)

101-101: ThemeToggle import is appropriate for SideMenu integration.


891-899: Side menu footer layout looks good with ThemeToggle.
Fits both collapsed and expanded layouts cleanly.

apps/webapp/app/routes/resources.preferences.theme.tsx (2)

6-8: Schema validation is tight and explicit.


10-27: Action flow is clean and consistent.
Good validation → persistence → success response shape.

apps/webapp/app/components/primitives/ThemeProvider.tsx (3)

22-34: System theme resolution helpers are clear and deterministic.


42-97: ThemeProvider wiring looks solid.
HTML class updates + persistence hooks are well‑structured.


99-105: useTheme guard is good.
Fail‑fast error keeps usage safe.

apps/webapp/app/root.tsx (3)

60-74: Theme preference loader addition is clean.
Defaulting to "dark" keeps a safe fallback.


92-108: ErrorBoundary wrapped consistently with ThemeProvider/ThemeScript.
Keeps theming behavior aligned even on error views.


116-135: App-level ThemeProvider integration looks good.
Loader-driven initial preference and login awareness are wired correctly.

apps/webapp/app/components/primitives/ThemeToggle.tsx (1)

10-14: Nice centralization of theme options.
Keeping the options in a single constant makes the UI mapping clean and consistent.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +107 to +121
// Script to prevent flash of wrong theme on initial load
// This should be injected into the <head> before any content renders
export function ThemeScript({ initialPreference }: { initialPreference?: ThemePreference }) {
const script = `
(function() {
var preference = ${JSON.stringify(initialPreference ?? null)} || localStorage.getItem('theme-preference') || 'dark';
var theme = preference;
if (preference === 'system') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
document.documentElement.classList.add(theme);
})();
`;

return <script dangerouslySetInnerHTML={{ __html: script }} />;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Clear existing theme classes before adding the new one.
ThemeScript only adds the class. Since the root HTML currently renders with dark, light preference can end up with both dark and light, keeping dark variants active until hydration. Remove existing theme classes first to prevent a flash of the wrong theme.

🩹 Suggested fix
-      document.documentElement.classList.add(theme);
+      var root = document.documentElement;
+      root.classList.remove('light', 'dark');
+      root.classList.add(theme);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Script to prevent flash of wrong theme on initial load
// This should be injected into the <head> before any content renders
export function ThemeScript({ initialPreference }: { initialPreference?: ThemePreference }) {
const script = `
(function() {
var preference = ${JSON.stringify(initialPreference ?? null)} || localStorage.getItem('theme-preference') || 'dark';
var theme = preference;
if (preference === 'system') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
document.documentElement.classList.add(theme);
})();
`;
return <script dangerouslySetInnerHTML={{ __html: script }} />;
// Script to prevent flash of wrong theme on initial load
// This should be injected into the <head> before any content renders
export function ThemeScript({ initialPreference }: { initialPreference?: ThemePreference }) {
const script = `
(function() {
var preference = ${JSON.stringify(initialPreference ?? null)} || localStorage.getItem('theme-preference') || 'dark';
var theme = preference;
if (preference === 'system') {
theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
var root = document.documentElement;
root.classList.remove('light', 'dark');
root.classList.add(theme);
})();
`;
return <script dangerouslySetInnerHTML={{ __html: script }} />;
🧰 Tools
🪛 ast-grep (0.40.5)

[warning] 120-120: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.3.13)

[error] 121-121: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🤖 Prompt for AI Agents
In `@apps/webapp/app/components/primitives/ThemeProvider.tsx` around lines 107 -
121, ThemeScript currently only adds a theme class which can leave both 'dark'
and 'light' present; update the injected script (in ThemeScript using the
initialPreference prop) to first remove any existing theme classes from
document.documentElement.classList (e.g., classList.remove('light','dark'))
before computing/adding the chosen theme so you never end up with both classes
during initial render/hydration.

Comment on lines +16 to +19
interface ThemeToggleProps {
className?: string;
isCollapsed?: boolean;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n apps/webapp/app/components/primitives/ThemeToggle.tsx | head -80

Repository: triggerdotdev/trigger.dev

Length of output: 3293


Use type aliases for props shapes.
These props are currently declared as interfaces; the repository guideline requires type aliases for TypeScript files.

♻️ Proposed change
-interface ThemeToggleProps {
+type ThemeToggleProps = {
   className?: string;
   isCollapsed?: boolean;
-}
+};

-interface ThemeToggleButtonsProps {
+type ThemeToggleButtonsProps = {
   className?: string;
-}
+};
🤖 Prompt for AI Agents
In `@apps/webapp/app/components/primitives/ThemeToggle.tsx` around lines 16 - 19,
Replace the interface ThemeToggleProps with a type alias: change the declaration
of ThemeToggleProps from an interface to a type (e.g., type ThemeToggleProps = {
className?: string; isCollapsed?: boolean; }) and update any references
(ThemeToggleProps) accordingly so the props shape uses a Type alias instead of
an interface in ThemeToggle.tsx.

@ericallam ericallam force-pushed the claude/slack-add-light-mode-dashboard-2ETGS branch from 1d63f2d to b5a1402 Compare January 30, 2026 10:44
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@apps/webapp/app/components/primitives/AppliedFilter.tsx`:
- Around line 6-8: The "secondary/small" style in AppliedFilter.tsx defines box
with both bg-secondary and group-hover:bg-secondary which makes the hover class
a no-op; update the "secondary/small" entry (the box string) to either remove
the redundant group-hover:bg-secondary or replace it with a distinct hover token
(e.g., group-hover:bg-secondary-hover or a different color utility) so hover
affordance is actually visible; ensure any corresponding hover token used
matches your design tokens and adjust the clear class only if it should also
reflect the new hover behavior.

In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx:
- Line 1348: Remove the trailing tab/whitespace at the end of the className
string that currently reads "flex w-full items-center gap-2 rounded-sm px-2 py-2
outline-none transition-colors focus-custom hover:bg-hover	" in the JSX element
in route.tsx; edit the className value used in that component so it ends with
"hover:bg-hover" (no trailing spaces or tabs) and scan the same JSX attribute
for any other accidental trailing whitespace to keep formatting consistent.
🧹 Nitpick comments (9)
apps/webapp/app/components/BlankStatePanels.tsx (1)

268-273: Consider semantic border/hover tokens for light mode consistency.

border-charcoal-* can be dark-mode biased. If the new theme system provides semantic border/hover tokens (e.g., border-grid-*, hover:bg-hover), it may be safer to align this selector with those to avoid low-contrast edges in light mode.

💡 Example adjustment (use available theme tokens)
-          className="w-fit border border-charcoal-600 bg-secondary hover:border-charcoal-550 hover:bg-secondary"
+          className="w-fit border border-grid-bright bg-secondary hover:border-grid hover:bg-hover"
apps/webapp/app/components/primitives/Select.tsx (1)

31-34: Minor: Redundant hover border class.

The hover:border-grid-bright class is redundant since the border is already border-grid-bright in the base state. Consider removing it for cleaner CSS unless there's a specific reason to keep it explicit.

🧹 Suggested simplification
  secondary: {
    button:
-      "bg-secondary focus-custom border border-grid-bright hover:text-text-bright hover:border-grid-bright text-text-bright hover:bg-hover",
+      "bg-secondary focus-custom border border-grid-bright text-text-bright hover:text-text-bright hover:bg-hover",
  },
apps/webapp/app/components/primitives/Pagination.tsx (1)

106-106: Consider updating border-charcoal-600 to a semantic border token.

The hover background is now theme-aware with hover:bg-secondary, but border-charcoal-600 remains hardcoded. This border will stay dark in light mode, potentially causing visual inconsistency.

If a semantic border token exists (e.g., border-grid-dimmed or similar based on the theme system), consider updating it for full light mode support.

apps/webapp/app/components/logs/LogsTable.tsx (1)

150-153: Verify visual distinction between selected and hovered states.

Both selected and non-selected hover states now use bg-hover. This means a selected row and a hovered (but not selected) row will have the same background color. This may reduce visual clarity when users are navigating the table.

Consider whether the selected state should use a distinct token (e.g., bg-hover-bright or a selection-specific token) to maintain clear visual feedback.

apps/webapp/app/tailwind.css (1)

221-226: Consider documenting the Streamdown code block visibility logic.

The !important overrides and the .dark\:hidden / .hidden.dark\:block selectors suggest this is working around Streamdown's internal theming. A brief comment explaining why this approach is needed would help future maintainers.

apps/webapp/app/components/primitives/ThemeProvider.tsx (3)

14-18: Use type instead of interface per coding guidelines.

The project guidelines specify using types over interfaces for TypeScript.

♻️ Proposed fix
-interface ThemeContextValue {
-  theme: Theme;
-  themePreference: ThemePreference;
-  setThemePreference: (preference: ThemePreference) => void;
-}
+type ThemeContextValue = {
+  theme: Theme;
+  themePreference: ThemePreference;
+  setThemePreference: (preference: ThemePreference) => void;
+};

As per coding guidelines: "Use types over interfaces for TypeScript"


36-40: Use type instead of interface here as well.

♻️ Proposed fix
-interface ThemeProviderProps {
-  children: ReactNode;
-  initialPreference?: ThemePreference;
-  isLoggedIn?: boolean;
-}
+type ThemeProviderProps = {
+  children: ReactNode;
+  initialPreference?: ThemePreference;
+  isLoggedIn?: boolean;
+};

As per coding guidelines: "Use types over interfaces for TypeScript"


73-90: Consider stabilizing the fetcher reference in the dependency array.

Including fetcher in the dependency array may cause setThemePreference to get a new identity on every render since useFetcher() returns a new object each time. This could trigger unnecessary re-renders in consumers that depend on setThemePreference stability.

♻️ Proposed fix using fetcher.submit directly
+  const fetcherSubmit = fetcher.submit;
+
   const setThemePreference = useCallback(
     (preference: ThemePreference) => {
       setThemePreferenceState(preference);
       setTheme(resolveTheme(preference));

       // Persist to server if logged in
       if (isLoggedIn) {
-        fetcher.submit(
+        fetcherSubmit(
           { theme: preference },
           { method: "POST", action: "/resources/preferences/theme" }
         );
       }

       // Also store in localStorage for non-logged-in users and faster hydration
       localStorage.setItem("theme-preference", preference);
     },
-    [isLoggedIn, fetcher]
+    [isLoggedIn, fetcherSubmit]
   );
apps/webapp/tailwind.config.js (1)

156-164: Unused light mode constants - consider removing or documenting their purpose.

The light* constants are defined but not referenced anywhere in the exported config. If they're kept as documentation/reference values for the CSS variables, add a comment clarifying this. Otherwise, consider removing them to avoid confusion.

💡 Option A: Add clarifying comment
-/** Light mode color values */
+/** Light mode color values (reference only - actual values defined in tailwind.css :root) */
 const lightTextDimmed = charcoal[500];
💡 Option B: Remove unused constants
-/** Light mode color values */
-const lightTextDimmed = charcoal[500];
-const lightTextBright = charcoal[800];
-const lightBackgroundBright = charcoal[100];
-const lightBackgroundDimmed = charcoal[200];
-const lightGridBright = charcoal[300];
-const lightGridDimmed = charcoal[200];
-const lightSecondary = charcoal[200];
-const lightTertiary = charcoal[100];
-
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d63f2d and b5a1402.

📒 Files selected for processing (59)
  • apps/webapp/app/components/AskAI.tsx
  • apps/webapp/app/components/BlankStatePanels.tsx
  • apps/webapp/app/components/code/ChartConfigPanel.tsx
  • apps/webapp/app/components/code/InlineCode.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/components/logs/LogsSearchInput.tsx
  • apps/webapp/app/components/logs/LogsTable.tsx
  • apps/webapp/app/components/navigation/EnvironmentSelector.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/navigation/SideMenuItem.tsx
  • apps/webapp/app/components/navigation/SideMenuSection.tsx
  • apps/webapp/app/components/primitives/AppliedFilter.tsx
  • apps/webapp/app/components/primitives/Calendar.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/ClipboardField.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/CopyableText.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/primitives/Input.tsx
  • apps/webapp/app/components/primitives/InputNumberStepper.tsx
  • apps/webapp/app/components/primitives/InputOTP.tsx
  • apps/webapp/app/components/primitives/PageHeader.tsx
  • apps/webapp/app/components/primitives/Pagination.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.tsx
  • apps/webapp/app/components/primitives/SegmentedControl.tsx
  • apps/webapp/app/components/primitives/Select.tsx
  • apps/webapp/app/components/primitives/Sheet.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/components/primitives/SimpleSelect.tsx
  • apps/webapp/app/components/primitives/Slider.tsx
  • apps/webapp/app/components/primitives/Switch.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
  • apps/webapp/app/components/primitives/ThemeToggle.tsx
  • apps/webapp/app/components/runs/v3/RunTag.tsx
  • apps/webapp/app/components/runs/v3/SpanTitle.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings._index/route.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/routes/account.tokens/route.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.streams.$streamKey/route.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/tailwind.css
  • apps/webapp/tailwind.config.js
✅ Files skipped from review due to trivial changes (6)
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam.streams.$streamKey/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/QueryHistoryPopover.tsx
  • apps/webapp/app/components/primitives/InputNumberStepper.tsx
  • apps/webapp/app/routes/account.tokens/route.tsx
  • apps/webapp/app/components/navigation/EnvironmentSelector.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.runs.$runParam/route.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/webapp/app/routes/resources.preferences.theme.tsx
  • apps/webapp/app/components/primitives/ThemeToggle.tsx
🧰 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}: Always import tasks from @trigger.dev/sdk, never use @trigger.dev/sdk/v3 or deprecated client.defineJob pattern
Every Trigger.dev task must be exported and have a unique id property with no timeouts in the run function

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/components/primitives/Slider.tsx
  • apps/webapp/app/components/navigation/SideMenuSection.tsx
  • apps/webapp/app/components/primitives/Sheet.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/CopyableText.tsx
  • apps/webapp/app/components/primitives/Input.tsx
  • apps/webapp/app/components/runs/v3/SpanTitle.tsx
  • apps/webapp/app/components/primitives/SimpleSelect.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/components/logs/LogsSearchInput.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings._index/route.tsx
  • apps/webapp/app/components/primitives/Switch.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/code/InlineCode.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/ClipboardField.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/components/navigation/SideMenuItem.tsx
  • apps/webapp/app/components/primitives/Select.tsx
  • apps/webapp/app/components/primitives/Pagination.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/components/AskAI.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/components/primitives/InputOTP.tsx
  • apps/webapp/app/components/primitives/Calendar.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/primitives/AppliedFilter.tsx
  • apps/webapp/app/components/BlankStatePanels.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/components/code/ChartConfigPanel.tsx
  • apps/webapp/app/components/primitives/SegmentedControl.tsx
  • apps/webapp/app/components/runs/v3/RunTag.tsx
  • apps/webapp/app/components/primitives/PageHeader.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/components/logs/LogsTable.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.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/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/components/primitives/Slider.tsx
  • apps/webapp/app/components/navigation/SideMenuSection.tsx
  • apps/webapp/app/components/primitives/Sheet.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/CopyableText.tsx
  • apps/webapp/app/components/primitives/Input.tsx
  • apps/webapp/app/components/runs/v3/SpanTitle.tsx
  • apps/webapp/app/components/primitives/SimpleSelect.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/components/logs/LogsSearchInput.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings._index/route.tsx
  • apps/webapp/app/components/primitives/Switch.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/code/InlineCode.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/ClipboardField.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/components/navigation/SideMenuItem.tsx
  • apps/webapp/app/components/primitives/Select.tsx
  • apps/webapp/app/components/primitives/Pagination.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/components/AskAI.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/components/primitives/InputOTP.tsx
  • apps/webapp/app/components/primitives/Calendar.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/primitives/AppliedFilter.tsx
  • apps/webapp/app/components/BlankStatePanels.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/components/code/ChartConfigPanel.tsx
  • apps/webapp/app/components/primitives/SegmentedControl.tsx
  • apps/webapp/app/components/runs/v3/RunTag.tsx
  • apps/webapp/app/components/primitives/PageHeader.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/components/logs/LogsTable.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use function declarations instead of default exports

Import from @trigger.dev/core using subpaths only, never import from root

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/components/primitives/Slider.tsx
  • apps/webapp/app/components/navigation/SideMenuSection.tsx
  • apps/webapp/app/components/primitives/Sheet.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/CopyableText.tsx
  • apps/webapp/app/components/primitives/Input.tsx
  • apps/webapp/app/components/runs/v3/SpanTitle.tsx
  • apps/webapp/app/components/primitives/SimpleSelect.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/components/logs/LogsSearchInput.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings._index/route.tsx
  • apps/webapp/app/components/primitives/Switch.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/code/InlineCode.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/ClipboardField.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/tailwind.config.js
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/components/navigation/SideMenuItem.tsx
  • apps/webapp/app/components/primitives/Select.tsx
  • apps/webapp/app/components/primitives/Pagination.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/components/AskAI.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/components/primitives/InputOTP.tsx
  • apps/webapp/app/components/primitives/Calendar.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/primitives/AppliedFilter.tsx
  • apps/webapp/app/components/BlankStatePanels.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/components/code/ChartConfigPanel.tsx
  • apps/webapp/app/components/primitives/SegmentedControl.tsx
  • apps/webapp/app/components/runs/v3/RunTag.tsx
  • apps/webapp/app/components/primitives/PageHeader.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/components/logs/LogsTable.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
apps/webapp/app/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Access all environment variables through the env export of env.server.ts instead of directly accessing process.env in the Trigger.dev webapp

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/components/primitives/Slider.tsx
  • apps/webapp/app/components/navigation/SideMenuSection.tsx
  • apps/webapp/app/components/primitives/Sheet.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/CopyableText.tsx
  • apps/webapp/app/components/primitives/Input.tsx
  • apps/webapp/app/components/runs/v3/SpanTitle.tsx
  • apps/webapp/app/components/primitives/SimpleSelect.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/components/logs/LogsSearchInput.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings._index/route.tsx
  • apps/webapp/app/components/primitives/Switch.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/code/InlineCode.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/ClipboardField.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/components/navigation/SideMenuItem.tsx
  • apps/webapp/app/components/primitives/Select.tsx
  • apps/webapp/app/components/primitives/Pagination.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/components/AskAI.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/components/primitives/InputOTP.tsx
  • apps/webapp/app/components/primitives/Calendar.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/primitives/AppliedFilter.tsx
  • apps/webapp/app/components/BlankStatePanels.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/components/code/ChartConfigPanel.tsx
  • apps/webapp/app/components/primitives/SegmentedControl.tsx
  • apps/webapp/app/components/runs/v3/RunTag.tsx
  • apps/webapp/app/components/primitives/PageHeader.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/components/logs/LogsTable.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
apps/webapp/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

apps/webapp/**/*.{ts,tsx}: When importing from @trigger.dev/core in 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

Access environment variables via env export from apps/webapp/app/env.server.ts, never use process.env directly

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/components/primitives/Slider.tsx
  • apps/webapp/app/components/navigation/SideMenuSection.tsx
  • apps/webapp/app/components/primitives/Sheet.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/CopyableText.tsx
  • apps/webapp/app/components/primitives/Input.tsx
  • apps/webapp/app/components/runs/v3/SpanTitle.tsx
  • apps/webapp/app/components/primitives/SimpleSelect.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/components/logs/LogsSearchInput.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings._index/route.tsx
  • apps/webapp/app/components/primitives/Switch.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/code/InlineCode.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/ClipboardField.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/components/navigation/SideMenuItem.tsx
  • apps/webapp/app/components/primitives/Select.tsx
  • apps/webapp/app/components/primitives/Pagination.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/components/AskAI.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/components/primitives/InputOTP.tsx
  • apps/webapp/app/components/primitives/Calendar.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/primitives/AppliedFilter.tsx
  • apps/webapp/app/components/BlankStatePanels.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/components/code/ChartConfigPanel.tsx
  • apps/webapp/app/components/primitives/SegmentedControl.tsx
  • apps/webapp/app/components/runs/v3/RunTag.tsx
  • apps/webapp/app/components/primitives/PageHeader.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/components/logs/LogsTable.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
**/*.{js,ts,jsx,tsx,json,md,yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier before committing

Files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/components/primitives/Slider.tsx
  • apps/webapp/app/components/navigation/SideMenuSection.tsx
  • apps/webapp/app/components/primitives/Sheet.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/CopyableText.tsx
  • apps/webapp/app/components/primitives/Input.tsx
  • apps/webapp/app/components/runs/v3/SpanTitle.tsx
  • apps/webapp/app/components/primitives/SimpleSelect.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/components/logs/LogsSearchInput.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings._index/route.tsx
  • apps/webapp/app/components/primitives/Switch.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/code/InlineCode.tsx
  • apps/webapp/app/routes/resources.orgs.$organizationSlug.select-plan.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/ClipboardField.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/routes/account._index/route.tsx
  • apps/webapp/tailwind.config.js
  • apps/webapp/app/components/code/TSQLResultsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/components/navigation/SideMenuItem.tsx
  • apps/webapp/app/components/primitives/Select.tsx
  • apps/webapp/app/components/primitives/Pagination.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/components/AskAI.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/components/primitives/InputOTP.tsx
  • apps/webapp/app/components/primitives/Calendar.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/primitives/AppliedFilter.tsx
  • apps/webapp/app/components/BlankStatePanels.tsx
  • apps/webapp/app/components/primitives/Callout.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/services/dashboardPreferences.server.ts
  • apps/webapp/app/components/code/ChartConfigPanel.tsx
  • apps/webapp/app/components/primitives/SegmentedControl.tsx
  • apps/webapp/app/components/runs/v3/RunTag.tsx
  • apps/webapp/app/components/primitives/PageHeader.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/components/logs/LogsTable.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
apps/webapp/app/services/**/*.server.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/webapp.mdc)

Separate testable services from configuration files; follow the pattern of realtimeClient.server.ts (testable service) and realtimeClientGlobal.server.ts (configuration) in the webapp

Files:

  • apps/webapp/app/services/dashboardPreferences.server.ts
**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/otel-metrics.mdc)

**/*.ts: When creating or editing OTEL metrics (counters, histograms, gauges), ensure metric attributes have low cardinality by using only enums, booleans, bounded error codes, or bounded shard IDs
Do not use high-cardinality attributes in OTEL metrics such as UUIDs/IDs (envId, userId, runId, projectId, organizationId), unbounded integers (itemCount, batchSize, retryCount), timestamps (createdAt, startTime), or free-form strings (errorMessage, taskName, queueName)
When exporting OTEL metrics via OTLP to Prometheus, be aware that the exporter automatically adds unit suffixes to metric names (e.g., 'my_duration_ms' becomes 'my_duration_ms_milliseconds', 'my_counter' becomes 'my_counter_total'). Account for these transformations when writing Grafana dashboards or Prometheus queries

Files:

  • apps/webapp/app/services/dashboardPreferences.server.ts
🧠 Learnings (15)
📚 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.query/AITabContent.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam._index/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
📚 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/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/AITabContent.tsx
  • apps/webapp/app/components/navigation/SideMenu.tsx
  • apps/webapp/app/components/primitives/CopyButton.tsx
  • apps/webapp/app/components/primitives/SheetV3.tsx
  • apps/webapp/app/components/runs/v3/TaskRunsTable.tsx
  • apps/webapp/app/components/primitives/Checkbox.tsx
  • apps/webapp/app/components/primitives/TextArea.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/components/primitives/Dialog.tsx
  • apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx
  • apps/webapp/app/components/primitives/Popover.tsx
  • apps/webapp/app/components/primitives/RadioButton.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.environment-variables.new/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.deployments.$deploymentParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.query/TRQLGuideContent.tsx
  • apps/webapp/app/root.tsx
  • apps/webapp/app/components/primitives/ThemeProvider.tsx
📚 Learning: 2025-09-03T14:35:52.384Z
Learnt from: myftija
Repo: triggerdotdev/trigger.dev PR: 2464
File: apps/webapp/app/utils/pathBuilder.ts:144-146
Timestamp: 2025-09-03T14:35:52.384Z
Learning: In the trigger.dev codebase, organization slugs are safe for URL query parameters and don't require URL encoding, as confirmed by the maintainer in apps/webapp/app/utils/pathBuilder.ts.

Applied to files:

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables.new/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} : Attach metadata to task runs using the metadata option when triggering, and access/update it inside runs using metadata functions

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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} : Subscribe to run updates using `runs.subscribeToRun()` for realtime monitoring of task execution

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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/TaskRunsTable.tsx
📚 Learning: 2026-01-15T11:50:06.067Z
Learnt from: CR
Repo: triggerdotdev/trigger.dev PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-15T11:50:06.067Z
Learning: Applies to **/*.{ts,tsx} : Every Trigger.dev task must be exported and have a unique `id` property with no timeouts in the run function

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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/TaskRunsTable.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/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 `schedules.task()` for scheduled/cron tasks instead of regular `task()`

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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 `runs.subscribeToBatch()` to subscribe to changes for all runs in a batch

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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.batchTrigger()` to trigger multiple runs of a single task with different payloads

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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 `.withStreams()` to subscribe to realtime streams from task metadata in addition to run changes

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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.batchTrigger()` to trigger multiple runs of a task from inside another task

Applied to files:

  • apps/webapp/app/components/runs/v3/TaskRunsTable.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 `runs.subscribeToRunsWithTag()` to subscribe to all runs with a specific tag

Applied to files:

  • apps/webapp/app/components/runs/v3/RunTag.tsx
🧬 Code graph analysis (6)
apps/webapp/app/components/navigation/SideMenu.tsx (3)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/ThemeToggle.tsx (1)
  • ThemeToggle (21-66)
apps/webapp/app/components/navigation/HelpAndFeedbackPopover.tsx (1)
  • HelpAndFeedback (32-254)
apps/webapp/app/components/primitives/Switch.tsx (1)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/routes/account._index/route.tsx (2)
apps/webapp/app/components/primitives/Label.tsx (1)
  • Label (25-41)
apps/webapp/app/components/primitives/ThemeToggle.tsx (1)
  • ThemeToggleButtons (72-100)
apps/webapp/app/services/dashboardPreferences.server.ts (1)
apps/webapp/app/services/session.server.ts (1)
  • UserFromSession (37-37)
apps/webapp/app/root.tsx (3)
apps/webapp/app/services/session.server.ts (1)
  • getUser (15-23)
apps/webapp/app/services/dashboardPreferences.server.ts (2)
  • ThemePreference (13-13)
  • ThemePreference (14-14)
apps/webapp/app/components/primitives/ThemeProvider.tsx (2)
  • ThemeScript (109-122)
  • ThemeProvider (42-97)
apps/webapp/app/components/primitives/Popover.tsx (1)
apps/webapp/app/components/primitives/Paragraph.tsx (1)
  • Paragraph (88-107)
🪛 ast-grep (0.40.5)
apps/webapp/app/components/primitives/ThemeProvider.tsx

[warning] 120-120: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html

(react-unsafe-html-injection)

🪛 Biome (2.3.13)
apps/webapp/app/tailwind.css

[error] 32-32: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 36-36: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 183-183: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 186-186: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 189-189: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 192-192: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 201-201: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 204-204: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 207-207: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 210-210: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 215-215: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 218-218: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 230-230: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)


[error] 233-233: Tailwind-specific syntax is disabled.

Enable tailwindDirectives in the css parser options, or remove this if you are not using Tailwind CSS.

(parse)

apps/webapp/app/components/primitives/ThemeProvider.tsx

[error] 121-121: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ 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 (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 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 (6, 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 (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 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 (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / packages / 🧪 Unit Tests: Packages (1, 1)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (2, 8)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: sdk-compat / Deno Runtime
  • GitHub Check: sdk-compat / Cloudflare Workers
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: sdk-compat / Node.js 20.20 (ubuntu-latest)
  • GitHub Check: sdk-compat / Node.js 22.12 (ubuntu-latest)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
  • GitHub Check: sdk-compat / Bun Runtime
  • GitHub Check: typecheck / typecheck

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 6 to 8
"secondary/small": {
box: "h-6 bg-secondary rounded pl-1.5 gap-1.5 text-xs divide-x divide-black/15 group-hover:bg-charcoal-600 group-hover:border-charcoal-550 text-text-bright border border-charcoal-600",
box: "h-6 bg-secondary rounded pl-1.5 gap-1.5 text-xs divide-x divide-black/15 group-hover:bg-secondary group-hover:border-charcoal-550 text-text-bright border border-charcoal-600",
clear: "size-6 text-text-bright hover:text-text-bright transition-colors",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Hover class is now a no-op for secondary/small.
bg-secondary + group-hover:bg-secondary removes hover feedback. If hover affordance is still desired, use a distinct token (e.g., a “hover” variant) or drop the redundant class to avoid confusion.

🤖 Prompt for AI Agents
In `@apps/webapp/app/components/primitives/AppliedFilter.tsx` around lines 6 - 8,
The "secondary/small" style in AppliedFilter.tsx defines box with both
bg-secondary and group-hover:bg-secondary which makes the hover class a no-op;
update the "secondary/small" entry (the box string) to either remove the
redundant group-hover:bg-secondary or replace it with a distinct hover token
(e.g., group-hover:bg-secondary-hover or a different color utility) so hover
affordance is actually visible; ensure any corresponding hover token used
matches your design tokens and adjust the clear class only if it should also
reflect the new hover behavior.

setIsRecentRunsPopoverOpen(false);
}}
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-charcoal-900 "
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-hover "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Trailing whitespace/tab character detected.

There appears to be a trailing tab character after hover:bg-hover in this className. This should be removed to maintain clean formatting.

🧹 Proposed fix
-                className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-hover	"
+                className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-hover"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-hover "
className="flex w-full items-center gap-2 rounded-sm px-2 py-2 outline-none transition-colors focus-custom hover:bg-hover"
🤖 Prompt for AI Agents
In
`@apps/webapp/app/routes/_app.orgs`.$organizationSlug.projects.$projectParam.env.$envParam.test.tasks.$taskParam/route.tsx
at line 1348, Remove the trailing tab/whitespace at the end of the className
string that currently reads "flex w-full items-center gap-2 rounded-sm px-2 py-2
outline-none transition-colors focus-custom hover:bg-hover	" in the JSX element
in route.tsx; edit the className value used in that component so it ends with
"hover:bg-hover" (no trailing spaces or tabs) and scan the same JSX attribute
for any other accidental trailing whitespace to keep formatting consistent.

@ericallam ericallam closed this Jan 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants