Skip to content

feat: dashboard openapi diffing#4042

Merged
chronark merged 12 commits intomainfrom
dashboard-openapi-diffing
Oct 1, 2025
Merged

feat: dashboard openapi diffing#4042
chronark merged 12 commits intomainfrom
dashboard-openapi-diffing

Conversation

@ogzhanolguncu
Copy link
Contributor

@ogzhanolguncu ogzhanolguncu commented Sep 30, 2025

What does this PR do?

This PR;

  • Adds proper diffing screen for scraped OpenAPI
  • Adds navigation from project details drawer to /openapi-diff
  • Adds missing portal component to Tooltip, that was causing some stacking issues.
  • Removed cursor-events-none thingy from so we can assign some title or for accessibility and better UX.

Fixes # (issue)

If there is not an issue for this, please create one first. This is used to tracking purposes and also helps use understand why this PR exists

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (refactoring code, technical debt, workflow improvements)
  • Enhancement (small improvements)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How should this be tested?

  • Create a project
  • Make deployment
  • Make another deployment but this time make some changes to openapi schema in demo-api
  • Go back to dashboard
  • Make sure you see this
image - During your first deployment you should see this, because we don't have anything to compare against image - Default look should be like this. We always pre-select current deployment on the right select image - Test clicking on project details diffing indicator and verify it actually takes you here.

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Contributing Guide
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand areas
  • Ran pnpm build
  • Ran pnpm fmt
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Unkey Docs if changes were necessary
Screen.Recording.2025-10-01.at.14.31.03.mov

@changeset-bot
Copy link

changeset-bot bot commented Sep 30, 2025

⚠️ No Changeset found

Latest commit: a1178cb

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

@vercel
Copy link

vercel bot commented Sep 30, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
dashboard Ready Ready Preview Comment Oct 1, 2025 11:40am
engineering Ready Ready Preview Comment Oct 1, 2025 11:40am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 30, 2025

📝 Walkthrough

Walkthrough

Adds a new OpenAPI Diff feature with a dedicated page, deployment selectors, and a client-side diff viewer. Integrates a compact OpenAPI diff section into project details. Refactors StatusIndicator to accept status and show tooltips. Adds navigation tab and context field. Removes legacy diff pages/components. Minor UI library tooltip/select adjustments.

Changes

Cohort / File(s) Summary
OpenAPI Diff feature (new page and components)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx, .../openapi-diff/deployment-select.tsx, .../openapi-diff/components/client.tsx, .../openapi-diff/components/empty.tsx
New page and components to select two deployments, fetch OpenAPI diff via TRPC, and render interactive diff results; includes empty/loading/error states and reusable DeploymentSelect and DiffViewerContent.
Project details: OpenAPI section
.../details/project-details-expandables/sections.tsx, .../details/project-details-expandables/detail-section.tsx, .../details/project-details-expandables/sections/open-api-diff.tsx
Adds “OpenAPI changes” section using new OpenApiDiff component; updates DetailItem types to allow null icon/label and conditional rendering logic.
StatusIndicator refactor
.../details/active-deployment-card/status-indicator.tsx
Introduces DiffStatus type; updates StatusIndicator to accept { status, withSignal, className }; adds InfoTooltip with content derived from status; conditional signal rendering.
Navigation
.../navigations/project-sub-navigation.tsx
Adds “Open API Diff” tab with icon; updates tab recognition and routing path.
Layout context
.../layout-provider.tsx, .../layout.tsx
Extends ProjectLayoutContextType with optional liveDeploymentId and provides it via context.
Remove legacy diff pages/components
.../diff/page.tsx, .../diff/[...compare]/page.tsx, .../diff/[...compare]/components/client.tsx
Deletes prior deployment diff selection page, diff view page, and old DiffViewer component implementation.
UI library tweaks
internal/ui/src/components/tooltip.tsx, internal/ui/src/components/form/select.tsx
TooltipContent now renders within a Portal; SelectItem style changes disabled behavior to opacity instead of pointer-events none.
TRPC minor edit
apps/dashboard/lib/trpc/routers/deploy/deployment/getOpenApiDiff.ts
Removes a top-of-file comment; no functional changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant P as OpenAPI Diff Page
  participant LQ as Live Query (deployments)
  participant S as DeploymentSelect
  participant Q as TRPC getOpenApiDiff
  participant V as DiffViewerContent

  U->>P: Navigate to /projects/:id/openapi-diff
  P->>LQ: Fetch deployments (latest first)
  LQ-->>P: Deployments list
  P->>S: Render From/To selectors (with disabled conflicts)

  U->>S: Choose From and To deployments
  S-->>P: onValueChange(selected IDs)

  alt Both selections present
    P->>Q: Query diff({ fromId, toId })
    Q-->>P: Diff data or error
    opt Loading
      P-->>U: Show loading state
    end
    alt Diff data
      P->>V: Render diff content (filters, groups)
      V-->>U: Interactive diff UI
    else Error
      P-->>U: Show error message
    end
  else Missing selection
    P-->>U: Show empty state
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

🕹️ oss.gg, :joystick: 150 points

Suggested reviewers

  • perkinsjr
  • mcstepp
  • chronark
  • MichaelUnkey

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description follows the template structure by providing a “What does this PR do?” summary, type of change section, testing instructions, and a checklist, but it leaves the “Fixes # (issue)” placeholder unfilled and does not specify any dependencies as required by the template. Additionally, marking every type of change without distinguishing the relevant ones dilutes the clarity expected in the type of change section. These omissions indicate that the description does not fully conform to the repository’s required template. Please replace the “Fixes # (issue)” placeholder with the actual issue number, list any dependencies, and select only the applicable change types to ensure the description fully adheres to the repository’s pull request template requirements.
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.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title uses the conventional commit prefix “feat:” and succinctly describes the primary addition of OpenAPI diffing functionality within the dashboard, accurately reflecting the main change in the pull request. It is concise, clear, and specific without extraneous details, enabling team members scanning the history to quickly understand the feature being introduced. The phrasing aligns directly with the objectives to add an OpenAPI diffing screen and navigation.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dashboard-openapi-diffing

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.

@vercel vercel bot temporarily deployed to Preview – engineering September 30, 2025 15:13 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard September 30, 2025 15:14 Inactive
@ogzhanolguncu ogzhanolguncu marked this pull request as ready for review October 1, 2025 11:37
@vercel vercel bot temporarily deployed to Preview – engineering October 1, 2025 11:39 Inactive
@vercel vercel bot temporarily deployed to Preview – dashboard October 1, 2025 11:40 Inactive
@github-actions
Copy link
Contributor

github-actions bot commented Oct 1, 2025

Thank you for following the naming conventions for pull request titles! 🙏

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: 4

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40e09e6 and a1178cb.

📒 Files selected for processing (17)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/status-indicator.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/detail-section.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections.tsx (2 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/diff/[...compare]/components/client.tsx (0 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/diff/[...compare]/page.tsx (0 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/diff/page.tsx (0 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout-provider.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/navigations/project-sub-navigation.tsx (3 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/empty.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/deployment-select.tsx (1 hunks)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (1 hunks)
  • apps/dashboard/lib/trpc/routers/deploy/deployment/getOpenApiDiff.ts (0 hunks)
  • internal/ui/src/components/form/select.tsx (1 hunks)
  • internal/ui/src/components/tooltip.tsx (1 hunks)
💤 Files with no reviewable changes (4)
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/diff/[...compare]/components/client.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/diff/[...compare]/page.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/diff/page.tsx
  • apps/dashboard/lib/trpc/routers/deploy/deployment/getOpenApiDiff.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-07-28T20:38:53.244Z
Learnt from: mcstepp
PR: unkeyed/unkey#3662
File: apps/dashboard/app/(app)/projects/[projectId]/diff/[...compare]/components/client.tsx:322-341
Timestamp: 2025-07-28T20:38:53.244Z
Learning: In apps/dashboard/app/(app)/projects/[projectId]/diff/[...compare]/components/client.tsx, mcstepp prefers to keep hardcoded endpoint logic in the getDiffType function during POC phases for demonstrating diff functionality, rather than implementing a generic diff algorithm. This follows the pattern of keeping simplified implementations for demonstration purposes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/empty.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx
  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx
📚 Learning: 2025-07-25T19:11:00.208Z
Learnt from: mcstepp
PR: unkeyed/unkey#3662
File: apps/dashboard/lib/trpc/routers/deployment/getOpenApiDiff.ts:110-147
Timestamp: 2025-07-25T19:11:00.208Z
Learning: In apps/dashboard/lib/trpc/routers/deployment/getOpenApiDiff.ts, the user mcstepp prefers to keep mock data fallbacks in POC/demonstration code for simplicity, even if it wouldn't be production-ready. This aligns with the PR being work-in-progress for demonstration purposes.

Applied to files:

  • apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx
🧬 Code graph analysis (6)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections.tsx (1)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx (1)
  • OpenApiDiff (26-108)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx (5)
internal/icons/src/icons/triangle-warning.tsx (1)
  • TriangleWarning (16-55)
internal/icons/src/icons/circle-warning.tsx (1)
  • CircleWarning (15-42)
internal/icons/src/icons/circle-xmark.tsx (1)
  • CircleXMark (16-62)
internal/icons/src/icons/chevron-down.tsx (1)
  • ChevronDown (15-35)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/diff/[...compare]/components/client.tsx (1)
  • changelog (32-986)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/navigations/project-sub-navigation.tsx (1)
internal/icons/src/icons/connections.tsx (1)
  • Connections (15-54)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/deployment-select.tsx (1)
internal/db/src/schema/deployments.ts (1)
  • deployments (9-54)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (5)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout-provider.tsx (1)
  • useProjectLayout (16-22)
internal/db/src/schema/deployments.ts (1)
  • deployments (9-54)
apps/dashboard/lib/trpc/server.ts (1)
  • trpc (7-14)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/deployment-select.tsx (1)
  • DeploymentSelect (19-85)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx (1)
  • DiffViewerContent (31-315)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx (5)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/status-indicator.tsx (2)
  • DiffStatus (5-5)
  • StatusIndicator (26-87)
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout-provider.tsx (1)
  • useProjectLayout (16-22)
apps/dashboard/lib/trpc/server.ts (1)
  • trpc (7-14)
apps/dashboard/lib/shorten-id.ts (1)
  • shortenId (5-54)
internal/icons/src/icons/arrow-right.tsx (1)
  • ArrowRight (15-48)
⏰ 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). (4)
  • GitHub Check: Test Go API Local / Test
  • GitHub Check: Test Packages / Test
  • GitHub Check: Build / Build
  • GitHub Check: Test API / API Test Local
🔇 Additional comments (31)
internal/ui/src/components/tooltip.tsx (1)

18-28: LGTM! Portal wrapping follows Radix UI best practices.

Wrapping TooltipContent with TooltipPrimitive.Portal ensures the tooltip renders at the document root, preventing z-index and overflow issues. This is the recommended pattern for Radix UI tooltips.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout-provider.tsx (1)

7-9: LGTM! Context type extended correctly.

The liveDeploymentId field is properly typed as optional and nullable, aligning with the value provided in layout.tsx. The optional nature ensures backward compatibility.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/empty.tsx (1)

1-31: LGTM! Well-crafted empty state component.

The component provides clear guidance with appropriate visual hierarchy and smooth animations. The inline animationDuration style on line 17 is acceptable for customizing the pulse animation timing.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/layout.tsx (3)

37-37: LGTM! Deployment ID extraction is correct.

The use of .at(0) safely handles empty arrays, returning undefined when no project is found, which is compatible with the context type.


61-61: LGTM! Context value properly includes deployment ID.

The liveDeploymentId is correctly passed to the context provider, making it available to all consumers via useProjectLayout().


39-45: Remove suppressions for collection.utils.refetch()

TanStack DB v0.1.x officially supports collection.utils.refetch() and auto-refetch handlers, so the @ts-expect-error and biome-ignore are no longer needed. Remove those suppressions and update types or dependencies if TS still complains. cite12

Likely an incorrect or invalid review comment.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/detail-section.tsx (3)

5-6: LGTM! Nullable props enable flexible layouts.

Making icon and label nullable allows for varied detail row configurations while maintaining type safety.


14-21: LGTM! Efficient early return for null cases.

The early return when both icon and label are absent allows the children to occupy the full width without unnecessary wrapper divs, improving layout flexibility.


26-31: LGTM! Conditional rendering prevents empty containers.

The conditional blocks ensure that icon and label wrappers only render when their respective values are present, avoiding unnecessary DOM elements.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/navigations/project-sub-navigation.tsx (1)

5-5: LGTM! Clean navigation extension.

The new "openapi-diff" tab is properly integrated with the existing navigation structure, following the same pattern as other tabs.

Also applies to: 50-50, 76-81

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections.tsx (2)

24-25: Type expansion enables flexible rendering.

Widening icon and label to accept null allows the new OpenAPI changes section to render without header elements.


38-48: LGTM! OpenAPI changes section integrated cleanly.

The new section is positioned prominently at the top and uses alignment: "start" for proper content layout.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/deployment-select.tsx (2)

19-84: LGTM! Comprehensive deployment selector.

The component handles all necessary states (loading, empty, disabled) and provides good UX with formatted dates, truncated messages, and tooltips for disabled items.


45-52: Verify Deployment.id null-safety

We couldn’t locate the Deployment type to confirm that id is always defined. Please verify that Deployment.id is non-optional in your schema; if it can be absent, guard the substring call (e.g. deployment.id?.substring(0, 7)).

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx (1)

52-66: LGTM! Edge cases handled appropriately.

The component gracefully handles the single-deployment scenario and the no-deployment case, providing appropriate UI for each state.

Also applies to: 68-107

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/components/client.tsx (7)

36-51: LGTM! Efficient state management with memoization.

The component uses useState for local UI state and useMemo for derived statistics, ensuring optimal re-render performance.


53-85: LGTM! Well-structured filtering and grouping logic.

The cascading memoization (filteredChanges → groupedChanges) ensures efficient updates and the grouping structure aligns well with OpenAPI endpoint organization.


93-111: LGTM! Consistent severity mapping.

The helper functions provide consistent icon and color mappings for all severity levels (breaking/warning/info).


113-121: LGTM! Appropriate empty state.

The early return for empty changelogs provides clear user feedback with contextual deployment labels.


126-151: LGTM! Clear and informative summary header.

The stats display provides quick insights into the nature and scope of changes with appropriate badges for breaking changes and warnings.


154-219: LGTM! Comprehensive and accessible filter controls.

The filter UI provides search, level selection, and operation filtering with a clear button to reset. The clear icon in the search input is a nice UX touch.


222-312: LGTM! Well-structured collapsible change groups.

The nested structure (path → operation → changes) with expand/collapse functionality makes it easy to navigate large diffs. The animation and color coding enhance the user experience.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/status-indicator.tsx (2)

5-11: LGTM! Clean type definitions.

The DiffStatus type and StatusIndicatorProps interface are well-defined, with sensible defaults for optional properties.


13-24: LGTM! Exhaustive tooltip content mapping.

The helper function provides clear, user-friendly tooltip messages for all status values.

apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/openapi-diff/page.tsx (7)

1-14: LGTM! Clean imports.

All necessary dependencies are imported for the diff page functionality.


15-21: LGTM! Proper state initialization.

Context and URL params are extracted correctly, and deployment state is initialized appropriately.


22-32: LGTM! Well-structured live query.

The deployments query correctly joins with environments, orders chronologically, and has a reasonable limit.


34-64: LGTM! Robust URL parameter handling.

The effect correctly prioritizes URL params, validates deployment existence, and falls back to live deployment appropriately.


66-78: LGTM! Properly gated TRPC query.

The diff query is correctly enabled only when both deployments are selected, preventing unnecessary API calls.


80-95: LGTM! Clean deployment label formatter.

The helper correctly formats deployment labels with branch and short SHA, with appropriate fallbacks.


97-214: LGTM! Well-structured render logic with proper state handling.

The component correctly handles:

  • Mutual exclusion between deployment selectors
  • Empty state when no deployments selected
  • Loading state during diff analysis
  • Error state with clear messaging
  • Content display with proper labels

The conditional rendering logic is clean and all edge cases are covered.

Comment on lines +65 to +66
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={index}
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

Replace placeholder biome-ignore explanation.

The ignore comment has a placeholder <explanation> instead of a meaningful justification.

Apply this diff:

-              <div
-                // biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
-                key={index}
+              <div
+                // biome-ignore lint/suspicious/noArrayIndexKey: Static animation array with stable indices
+                key={index}
📝 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
// biome-ignore lint/suspicious/noArrayIndexKey: <explanation>
key={index}
<div
// biome-ignore lint/suspicious/noArrayIndexKey: Static animation array with stable indices
key={index}
🤖 Prompt for AI Agents
In
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/active-deployment-card/status-indicator.tsx
around lines 65-66, the biome-ignore comment currently contains a placeholder
"<explanation>"; replace it with a concise, factual justification explaining why
using the array index as the React key is acceptable here (for example: "items
are static/never reordered/uniquely scoped to this render so index stability is
guaranteed"), or alternatively remove the ignore and refactor to use a stable
unique id for the key; ensure the justification mentions the specific constraint
(static list, no reordering, or key derived elsewhere) so the lint suppression
is meaningful.

Comment on lines +44 to +47
const diff = trpc.deploy.deployment.getOpenApiDiff.useQuery({
newDeploymentId: newDeployment?.id ?? "",
oldDeploymentId: oldDeployment?.id ?? "",
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify TRPC query behavior with empty deployment IDs.

When newDeployment or oldDeployment are undefined, the query receives empty strings. Ensure the backend gracefully handles this case or add a guard to skip the query.


🏁 Script executed:

#!/bin/bash
# Check the getOpenApiDiff implementation to verify empty string handling
ast-grep --pattern 'getOpenApiDiff$$$'
rg -nP --type=ts -C5 'getOpenApiDiff' apps/dashboard/lib/trpc/routers/deployment/

Length of output: 83


🏁 Script executed:

#!/bin/bash
# locate implementation file for getOpenApiDiff
files=$(rg -l "getOpenApiDiff" -g '*.ts' apps/dashboard/lib/trpc/routers || true)
echo "Found files:" 
echo "$files"
# inspect occurrences in each file
for file in $files; do
  echo "--- File: $file ---"
  rg -n -C5 "getOpenApiDiff" "$file"
done

Length of output: 1945


Guard the TRPC query from running with empty IDs
The router’s input schema accepts empty strings and there’s no check in the procedure, so calling it with missing IDs can error. Wrap the useQuery in enabled: !!newDeployment?.id && !!oldDeployment?.id (or skip the hook when either ID is empty) [apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx:44-47]

🤖 Prompt for AI Agents
In
apps/dashboard/app/(app)/[workspaceSlug]/projects/[projectId]/details/project-details-expandables/sections/open-api-diff.tsx
around lines 44 to 47, the TRPC useQuery is called with possibly empty
deployment IDs which can cause the procedure to error; guard the query by adding
an enabled condition that only runs the query when both IDs are non-empty (e.g.
pass enabled: !!newDeployment?.id && !!oldDeployment?.id) or skip calling
useQuery entirely when either ID is missing so the hook does not execute with
empty strings.

Comment on lines +49 to +50
// @ts-expect-error I have no idea why this whines about type diff
const status = getDiffStatus(diff.data);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Investigate and document the type mismatch.

The @ts-expect-error comment indicates uncertainty about the type issue. This should be investigated and either fixed or documented with a clear explanation of why the type mismatch is expected.

If the types genuinely conflict and there's a valid reason, update the comment to be more specific:

-  // @ts-expect-error I have no idea why this whines about type diff
+  // @ts-expect-error GetOpenApiDiffResponse type doesn't match getDiffStatus parameter due to [specific reason]
   const status = getDiffStatus(diff.data);

Or investigate and fix the underlying type issue.

📝 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
// @ts-expect-error I have no idea why this whines about type diff
const status = getDiffStatus(diff.data);
// @ts-expect-error GetOpenApiDiffResponse type doesn't match getDiffStatus parameter due to [specific reason]
const status = getDiffStatus(diff.data);

Comment on lines 139 to 143
className={cn(
"relative flex w-full cursor-default select-none items-center rounded-md py-1.5 pl-2 pr-8 text-[13px] outline-none",
"text-gray-12 hover:bg-gray-4 focus:bg-gray-5 data-[disabled]:opacity-50 data-[disabled]:pointer-events-none",
"text-gray-12 hover:bg-gray-4 focus:bg-gray-5 data-[disabled]:opacity-50",
className,
)}
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

Restore disabled-item interaction guard.

Dropping data-[disabled]:pointer-events-none means disabled options now pick up the existing hover:bg-gray-4/focus:bg-gray-5 styles, so they highlight and behave like active options even though they stay non-selectable. Please keep the pointer-events guard (or explicitly noop the hover/focus states) while adding the opacity fade, e.g. data-[disabled]:pointer-events-none data-[disabled]:opacity-50.

🤖 Prompt for AI Agents
In internal/ui/src/components/form/select.tsx around lines 139 to 143, disabled
items lost the pointer-events guard and now still receive hover/focus styles;
restore the interaction guard and keep the opacity change by adding the Tailwind
data attribute for pointer events to the class list (e.g. include
data-[disabled]:pointer-events-none alongside data-[disabled]:opacity-50) so
disabled options don’t respond to hover/focus while still showing the faded
appearance.

@chronark chronark merged commit 4d9c585 into main Oct 1, 2025
23 checks passed
@chronark chronark deleted the dashboard-openapi-diffing branch October 1, 2025 12:49
@coderabbitai coderabbitai bot mentioned this pull request Oct 1, 2025
18 tasks
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.

2 participants