Skip to content

Conversation

@samejr
Copy link
Member

@samejr samejr commented Dec 31, 2025

UI Improvements to the Concurrency page:

  • Truncates long branch names and includes a tooltip
  • The Tables have a new variant if you don't want the rows to highlight on hover
  • Small fix to pluralize some words in the purchase modal
  • Fix to prevent tooltip buttons being type=submit
  • Updates the /limits docs page to include purchasing more concurrency
  • Adds a clear banner when you have a positive balance of unallocated concurrency
CleanShot.2025-12-30.at.17.06.15.mp4

@changeset-bot
Copy link

changeset-bot bot commented Dec 31, 2025

⚠️ No Changeset found

Latest commit: 0730342

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 Dec 31, 2025

Walkthrough

This pull request adds configurable tooltip placement props to environment labels, updates button and table styling patterns, enhances tooltip accessibility, and revises the concurrency management UI. Changes include introducing tooltipSide and tooltipSideOffset props to EnvironmentCombo and EnvironmentLabel, adding a new "bright/no-hover" table variant, updating the concurrency route to use the new variant with additional UI elements (icons and pluralized text), adding type="button" to TooltipTrigger, and revising documentation for Pro tier concurrency acquisition via the dashboard.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description check ❓ Inconclusive The description provides a solid overview of changes but lacks testing details, issue closure reference, and checklist items required by the template. Add testing steps explaining how the UI improvements were validated, include the issue number (Closes #), and complete the contributing guide checklist items.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change as UI improvements to the concurrency page, directly aligned with the changeset's primary focus.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between edf5b14 and 0730342.

📒 Files selected for processing (6)
  • apps/webapp/app/components/environments/EnvironmentLabel.tsx
  • apps/webapp/app/components/primitives/Buttons.tsx
  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/components/primitives/Tooltip.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx
  • docs/limits.mdx
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{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

Files:

  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/components/environments/EnvironmentLabel.tsx
  • apps/webapp/app/components/primitives/Tooltip.tsx
  • apps/webapp/app/components/primitives/Buttons.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/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/Table.tsx
  • apps/webapp/app/components/environments/EnvironmentLabel.tsx
  • apps/webapp/app/components/primitives/Tooltip.tsx
  • apps/webapp/app/components/primitives/Buttons.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx
**/*.{ts,tsx,js,jsx}

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

Use function declarations instead of default exports

Files:

  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/components/environments/EnvironmentLabel.tsx
  • apps/webapp/app/components/primitives/Tooltip.tsx
  • apps/webapp/app/components/primitives/Buttons.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.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/components/primitives/Table.tsx
  • apps/webapp/app/components/environments/EnvironmentLabel.tsx
  • apps/webapp/app/components/primitives/Tooltip.tsx
  • apps/webapp/app/components/primitives/Buttons.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.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

Files:

  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/components/environments/EnvironmentLabel.tsx
  • apps/webapp/app/components/primitives/Tooltip.tsx
  • apps/webapp/app/components/primitives/Buttons.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx
**/*.{js,ts,jsx,tsx,json,md,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

Format code using Prettier

Files:

  • apps/webapp/app/components/primitives/Table.tsx
  • apps/webapp/app/components/environments/EnvironmentLabel.tsx
  • apps/webapp/app/components/primitives/Tooltip.tsx
  • apps/webapp/app/components/primitives/Buttons.tsx
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx
🧠 Learnings (5)
📚 Learning: 2025-11-14T16:03:06.917Z
Learnt from: matt-aitken
Repo: triggerdotdev/trigger.dev PR: 2681
File: apps/webapp/app/services/platform.v3.server.ts:258-302
Timestamp: 2025-11-14T16:03:06.917Z
Learning: In `apps/webapp/app/services/platform.v3.server.ts`, the `getDefaultEnvironmentConcurrencyLimit` function intentionally throws an error (rather than falling back to org.maximumConcurrencyLimit) when the billing client returns undefined plan limits. This fail-fast behavior prevents users from receiving more concurrency than their plan entitles them to. The org.maximumConcurrencyLimit fallback is only for self-hosted deployments where no billing client exists.

Applied to files:

  • docs/limits.mdx
📚 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} : Control concurrency using the `queue` property with `concurrencyLimit` option

Applied to files:

  • docs/limits.mdx
📚 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.concurrency/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.concurrency/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/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx
🧬 Code graph analysis (2)
apps/webapp/app/components/environments/EnvironmentLabel.tsx (1)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
apps/webapp/app/components/primitives/Buttons.tsx (1)
apps/webapp/app/utils/cn.ts (1)
  • cn (77-79)
⏰ 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). (23)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (1, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (6, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (7, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (5, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (3, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (7, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (6, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (4, 8)
  • GitHub Check: units / webapp / 🧪 Unit Tests: Webapp (2, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (8, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (5, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (3, 8)
  • GitHub Check: units / internal / 🧪 Unit Tests: Internal (1, 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 - npm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
  • GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
  • GitHub Check: typecheck / typecheck
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (10)
apps/webapp/app/components/primitives/Tooltip.tsx (1)

88-88: LGTM! Prevents unintended form submissions.

Adding type="button" ensures that tooltip triggers don't accidentally submit forms when clicked. This is a good accessibility and UX improvement.

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

392-392: LGTM! Improves default button width behavior.

The change from an empty string to "w-fit" ensures that link buttons have a constrained width by default when fullWidth={false}. This aligns with the PR objective to prevent buttons from spanning 100% width unnecessarily.

docs/limits.mdx (1)

16-16: LGTM! Documentation updated to reflect dashboard-based purchase flow.

The documentation now accurately directs users to the Concurrency page in the dashboard for purchasing additional concurrency, which aligns with the UI changes in this PR.

apps/webapp/app/components/environments/EnvironmentLabel.tsx (1)

54-55: LGTM! Enables configurable tooltip placement for truncated environment labels.

The addition of tooltipSide and tooltipSideOffset props with sensible defaults ("right" and 34 respectively) provides flexibility for tooltip positioning while maintaining backward compatibility. The disableHoverableContent prop on line 133 ensures proper tooltip behavior.

Also applies to: 60-61, 69-73, 81-82, 86-87, 130-130, 132-133

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

18-25: LGTM! New table variant disables row hover highlighting.

The "bright/no-hover" variant correctly implements a table style without hover effects by using bg-transparent for the header and cell hover states. This aligns with the PR objective to add a table variant that disables row hover highlighting.

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx (5)

4-4: LGTM! New imports for UI enhancements.

The ArrowDownIcon import supports the new unallocated concurrency banner, and the simplur import enables proper pluralization throughout the UI.

Also applies to: 22-22


336-336: LGTM! Consistent use of the new table variant.

All tables now use variant="bright/no-hover" to disable row hover highlighting, providing a cleaner, more static appearance for the concurrency management UI.

Also applies to: 456-456, 550-550


384-446: LGTM! Clear visual feedback for unallocated concurrency.

The implementation provides excellent user experience:

  • The banner (lines 431-440) clearly indicates when there's unallocated concurrency with success styling and an animated arrow icon
  • Conditional styling based on allocationModified and unallocated states provides appropriate visual feedback
  • The save/reset actions are well-positioned and intuitive

474-479: LGTM! Proper tooltip configuration for truncated environment labels.

The tooltipSideOffset={6} and tooltipSide="top" props ensure tooltips display correctly for truncated branch names in the compact table layout, with className="max-w-[18ch]" enforcing the truncation.


709-709: LGTM! Proper pluralization using simplur.

The simplur template literals correctly pluralize "bundle"/"bundles" based on the count, improving the readability of the purchase modal text.

Also applies to: 731-734, 753-753


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.

@diffray-bot
Copy link

Changes Summary

This PR enhances the concurrency management page UI with several UX improvements: truncating long branch names with tooltips, adding a new table variant to remove hover states, fixing tooltip button types for accessibility, using proper pluralization for bundle labels, and displaying a clear banner when unallocated concurrency is available. The documentation is also updated to reflect the new self-service concurrency purchasing feature.

Type: feature

Components Affected: EnvironmentLabel component, Table component, Tooltip component, Concurrency management route, Documentation (limits page)

Files Changed
File Summary Change Impact
...pp/components/environments/EnvironmentLabel.tsx Adds truncation detection with ResizeObserver and conditionally displays tooltip for long branch names; adds configurable tooltip positioning props. ✏️ 🟡
...ps/webapp/app/components/primitives/Buttons.tsx Adds 'w-fit' class to LinkButton when not fullWidth to prevent spanning 100% width by default. ✏️ 🟢
...apps/webapp/app/components/primitives/Table.tsx Introduces new 'bright/no-hover' table variant that disables row hover background changes while maintaining other styling. ✏️ 🟡
...ps/webapp/app/components/primitives/Tooltip.tsx Adds explicit 'type=button' attribute to TooltipTrigger to prevent default form submission behavior. ✏️ 🟢
...rojectParam.env.$envParam.concurrency/route.tsx Applies 'bright/no-hover' variant to tables, adds green banner for positive unallocated concurrency balance, uses 'simplur' for dynamic pluralization of 'bundle/bundles', and enhances EnvironmentCombo with custom tooltip positioning. ✏️ 🔴
/tmp/workspace/docs/limits.mdx Updates concurrency limits documentation to direct users to the dashboard for purchasing, replacing outdated contact-based approach. ✏️ 🟢
Architecture Impact
  • New Patterns: ResizeObserver pattern for detecting text truncation, Configurable tooltip positioning through props, Table variant system for conditional styling
  • Dependencies: added: simplur library (for pluralization)
  • Coupling: Increased coupling between EnvironmentCombo and EnvironmentLabel through tooltip positioning props

Risk Areas: ResizeObserver lifecycle management - ensures proper cleanup with dependency arrays, Tooltip positioning edge cases - custom side offsets and sides may have unexpected behavior in certain viewport positions, Table variant proliferation - new variant adds complexity; future maintenance may require consolidation, simplur library - introduces new external dependency for string pluralization (consider lightweight alternative if not already standard)

Suggestions
  • Consider memoizing the isTruncated calculation in EnvironmentLabel to prevent unnecessary ResizeObserver re-registration
  • The new table variant could benefit from documentation explaining use cases (when to use bright vs bright/no-hover)
  • Consider adding unit tests for truncation detection with various text lengths

Full review in progress... | Powered by diffray

Comment on lines +88 to 89
type="button"
tabIndex={-1}

Choose a reason for hiding this comment

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

🟡 MEDIUM - Intentional tabIndex=-1 on tooltip trigger
Agent: react

Category: quality

Description:
SimpleTooltip uses tabIndex={-1} on type='button' element. This is likely intentional to prevent tooltip triggers from being focusable while still being mouse-interactive, but should be documented.

Suggestion:
Add a comment explaining why tabIndex={-1} is used intentionally, or consider if keyboard accessibility should be supported.

Confidence: 60%
Rule: ts_use_appropriate_tabindex_values
Review ID: fb475f6c-79ba-4905-bbc9-50e570158b3a
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

@diffray-bot
Copy link

Review Summary

Free public review - Want AI code reviews on your PRs? Check out diffray.ai

Validated 26 issues: 6 kept (1 critical bug, 1 medium bug, 4 low-value docs/style), 20 filtered (mostly low-value performance/style suggestions and documentation requests)

Issues Found: 5

💬 See 1 individual line comment(s) for details.

📊 4 unique issue type(s) across 5 location(s)

📋 Full issue list (click to expand)

🟠 HIGH - Missing destructuring of tryCatch result

Agent: refactoring

Category: bug

File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:110-113

Description: tryCatch() returns [error, result] tuple but line 110 assigns entire tuple to plans without destructuring. The check if (!plans) on line 111 will never be true since arrays are always truthy.

Suggestion: Change const plans = await tryCatch(getPlans()); to const [error, plans] = await tryCatch(getPlans()); and check if (error) instead of if (!plans).

Confidence: 95%

Rule: bug_missing_await


🟡 MEDIUM - useEffect dependency uses method call result

Agent: react

Category: bug

File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:608-617

Description: Dependency array contains searchParams.get('success') which calls a method on each render. Should extract value before effect to ensure stable dependency.

Suggestion: Extract before effect: const success = searchParams.get('success'); then use [success] in dependency array.

Confidence: 75%

Rule: ts_handle_async_operations_with_proper_erro


🟡 MEDIUM - Unsafe 'as any' type assertion with TODO (2 occurrences)

Agent: react

Category: bug

📍 View all locations
File Description Suggestion Confidence
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:296-301 Line 296 uses lastSubmission as any with explicit TODO comment indicating known technical debt. Ty... Define proper type for lastSubmission based on conform library's expected types. 70%
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:593-598 Same pattern as line 296 - lastSubmission as any with TODO comment. Technical debt duplicated acro... Create a shared type definition and apply to both usages. 70%

Rule: ts_avoid_unsafe_type_assertions


🟡 MEDIUM - Intentional tabIndex=-1 on tooltip trigger

Agent: react

Category: quality

File: apps/webapp/app/components/primitives/Tooltip.tsx:88-89

Description: SimpleTooltip uses tabIndex={-1} on type='button' element. This is likely intentional to prevent tooltip triggers from being focusable while still being mouse-interactive, but should be documented.

Suggestion: Add a comment explaining why tabIndex={-1} is used intentionally, or consider if keyboard accessibility should be supported.

Confidence: 60%

Rule: ts_use_appropriate_tabindex_values


ℹ️ 4 issue(s) outside PR diff (click to expand)

These issues were found in lines not modified in this PR.

🟠 HIGH - Missing destructuring of tryCatch result

Agent: refactoring

Category: bug

File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:110-113

Description: tryCatch() returns [error, result] tuple but line 110 assigns entire tuple to plans without destructuring. The check if (!plans) on line 111 will never be true since arrays are always truthy.

Suggestion: Change const plans = await tryCatch(getPlans()); to const [error, plans] = await tryCatch(getPlans()); and check if (error) instead of if (!plans).

Confidence: 95%

Rule: bug_missing_await


🟡 MEDIUM - useEffect dependency uses method call result

Agent: react

Category: bug

File: apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:608-617

Description: Dependency array contains searchParams.get('success') which calls a method on each render. Should extract value before effect to ensure stable dependency.

Suggestion: Extract before effect: const success = searchParams.get('success'); then use [success] in dependency array.

Confidence: 75%

Rule: ts_handle_async_operations_with_proper_erro


🟡 MEDIUM - Unsafe 'as any' type assertion with TODO (2 occurrences)

Agent: react

Category: bug

📍 View all locations
File Description Suggestion Confidence
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:296-301 Line 296 uses lastSubmission as any with explicit TODO comment indicating known technical debt. Ty... Define proper type for lastSubmission based on conform library's expected types. 70%
apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.concurrency/route.tsx:593-598 Same pattern as line 296 - lastSubmission as any with TODO comment. Technical debt duplicated acro... Create a shared type definition and apply to both usages. 70%

Rule: ts_avoid_unsafe_type_assertions



Review ID: fb475f6c-79ba-4905-bbc9-50e570158b3a
Rate it 👍 or 👎 to improve future reviews | Powered by diffray

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