Skip to content

chore: version dependencies ui#1086

Merged
adityachoudhari26 merged 3 commits intomainfrom
deps-ui
Apr 29, 2026
Merged

chore: version dependencies ui#1086
adityachoudhari26 merged 3 commits intomainfrom
deps-ui

Conversation

@adityachoudhari26
Copy link
Copy Markdown
Member

@adityachoudhari26 adityachoudhari26 commented Apr 29, 2026

fixes #1080

Summary by CodeRabbit

  • New Features
    • Added dependency tracking and visualization for deployment versions, showing which environment targets satisfy or fail dependency constraints.
    • New Dependencies section displays dependency status and version information for release targets, with per-dependency satisfaction indicators.

Copilot AI review requested due to automatic review settings April 29, 2026 21:03
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 29, 2026

Warning

Rate limit exceeded

@adityachoudhari26 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 45 minutes and 58 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ef664aed-76b4-499a-88f8-c3f843c56f38

📥 Commits

Reviewing files that changed from the base of the PR and between 0fea90c and a6218dc.

📒 Files selected for processing (3)
  • apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx
  • packages/trpc/src/routes/deployment-versions.ts
  • packages/trpc/src/routes/release-targets.ts
📝 Walkthrough

Walkthrough

This PR implements the UI surface for deployment dependencies. It adds backend TRPC endpoints to fetch dependency metadata and current versions, creates new frontend components to display dependencies with version selector evaluation, and integrates these components into both the deployment version view and release target page.

Changes

Cohort / File(s) Summary
Frontend Dependency Components
apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx, apps/web/app/routes/ws/deployments/_components/release-targets/Dependencies.tsx
New UI components that fetch and display deployment dependencies with version satisfaction evaluation using cel-js, polling with 15s refetch intervals, and expandable dependency lists showing selector expressions and current deployed versions.
Component & Page Integration
apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/DeploymentVersion.tsx, apps/web/app/routes/ws/deployments/page.$deploymentId.release-targets.$releaseTargetKey.tsx
Updated DeploymentVersion to require environment.name, handles null data safely, and renders new DependencyDetail section. Release targets page now imports and renders Dependencies component when key parsing succeeds.
Backend Dependency Endpoints
packages/trpc/src/routes/deployment-versions.ts, packages/trpc/src/routes/release-targets.ts
New TRPC procedures that fetch deployment version metadata, retrieve dependency relationships, resolve current deployed versions per target using database queries with joins on releases and jobs, and return dependency objects with version selectors and current versions.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DependencyDetail as DependencyDetail Component
    participant TRPC as TRPC deploymentVersions.dependencies
    participant DB as Database
    participant CEL as cel-js Evaluator
    participant UI as Dependency Dialog UI

    User->>DependencyDetail: Render with versionId
    DependencyDetail->>TRPC: useQuery({ versionId })
    TRPC->>DB: Get deploymentVersion metadata
    DB-->>TRPC: version data
    TRPC->>DB: Query deploymentVersionDependency relationships
    DB-->>TRPC: dependency edges
    TRPC->>DB: Fetch target environment/resource pairs
    DB-->>TRPC: targets
    TRPC->>DB: Query release jobs for current versions per target
    DB-->>TRPC: current versions
    TRPC-->>DependencyDetail: { version, dependencies[] }
    DependencyDetail->>CEL: Evaluate each dependency.versionSelector against currentVersion
    CEL-->>DependencyDetail: satisfied/unsatisfied per target
    DependencyDetail->>DependencyDetail: Aggregate satisfaction counts
    DependencyDetail->>UI: Render with summary and expandable dependency list
    UI-->>User: Display satisfied/blocked status and details
Loading
sequenceDiagram
    participant User
    participant Dependencies as Dependencies Component
    participant TRPC as TRPC releaseTargets.dependencies
    participant DB as Database
    participant CEL as cel-js Evaluator
    participant Card as Dependency Card UI

    User->>Dependencies: Render with deploymentId, environmentId, resourceId
    Dependencies->>TRPC: useQuery({ deploymentId, environmentId, resourceId })
    TRPC->>DB: Find desired or latest deploymentVersion
    DB-->>TRPC: version
    TRPC->>DB: Query deploymentVersionDependency for version
    DB-->>TRPC: dependencies
    TRPC->>DB: Find most recent successful release for each dependency
    DB-->>TRPC: currentVersion per dependency
    TRPC-->>Dependencies: { version, dependencies[] }
    Dependencies->>CEL: Evaluate versionSelector against currentVersion
    CEL-->>Dependencies: satisfied/unsatisfied per dependency
    Dependencies->>Dependencies: Compute satisfiedCount/total
    Dependencies->>Card: Render header with satisfaction ratio
    Card->>Card: Render per-dependency rows with selector and version
    Card-->>User: Display card with satisfied/unsatisfied indicators
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested Reviewers

  • jsbroks

Poem

🐰 Dependencies bloom in the web's garden fair,
With selectors dancing through the air,
Version shadows tracked with care,
Satisfaction counts float everywhere—
A hoppy release, beyond compare! 🌿✨

🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'chore: version dependencies ui' is vague and does not clearly convey what changes were made; it uses generic terminology without specifics. Consider a more descriptive title like 'feat: add deployment dependencies UI for version evaluation' that better reflects the substantial feature additions.
Linked Issues check ❓ Inconclusive The PR implements dependency UI surfacing on release target pages and dependency details dialogs, partially addressing issue #1080's requirement to show dependencies on deployment pages and indicate blocked releases. Verify whether the PR fully implements management controls (add/edit/remove dependencies) or if those are deferred to a follow-up, and confirm the blocked dependency indication is complete.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Out of Scope Changes check ✅ Passed All changes directly support displaying deployment dependencies and their version satisfaction status in the UI, aligned with issue #1080 objectives.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deps-ui

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
Review rate limit: 0/1 reviews remaining, refill in 45 minutes and 58 seconds.

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

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Surfaces deployment-version dependency status in the web UI (issue #1080) by adding TRPC endpoints that return dependency edges plus “current” upstream versions, and by rendering those dependencies on release-target and policy-evaluation views.

Changes:

  • Add dependencies queries to TRPC releaseTargets and deploymentVersions routers to fetch declared dependency edges and current upstream versions.
  • Show a Dependencies card on the release-target evaluations page.
  • Add a dependency detail dialog to the environment version decision UI.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
packages/trpc/src/routes/release-targets.ts New releaseTargets.dependencies query returning declared dependencies and current upstream version per dependency.
packages/trpc/src/routes/deployment-versions.ts New deploymentVersions.dependencies query returning dependencies and per-target current upstream versions.
apps/web/app/routes/ws/deployments/page.$deploymentId.release-targets.$releaseTargetKey.tsx Wires the new Dependencies UI into the release-target page.
apps/web/app/routes/ws/deployments/_components/release-targets/Dependencies.tsx New card UI that evaluates dependency selectors client-side and displays satisfaction status.
apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx New dialog UI to summarize blocked targets and drill into dependency satisfaction per target.
apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/DeploymentVersion.tsx Adds the dependency detail component into the version decision stack.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +271 to +317
if (resourceIds.length > 0) {
await Promise.all(
edges.map(async (edge) => {
const rows = await ctx.db
.select({
resourceId: schema.release.resourceId,
versionId: schema.release.versionId,
tag: schema.deploymentVersion.tag,
name: schema.deploymentVersion.name,
status: schema.deploymentVersion.status,
})
.from(schema.release)
.innerJoin(
schema.releaseJob,
eq(schema.releaseJob.releaseId, schema.release.id),
)
.innerJoin(schema.job, eq(schema.job.id, schema.releaseJob.jobId))
.innerJoin(
schema.deploymentVersion,
eq(schema.deploymentVersion.id, schema.release.versionId),
)
.where(
and(
eq(schema.release.deploymentId, edge.dependencyDeploymentId),
inArray(schema.release.resourceId, resourceIds),
eq(schema.job.status, "successful"),
isNotNull(schema.job.completedAt),
),
)
.orderBy(desc(schema.job.completedAt));

const byResource = new Map<
string,
{ id: string; tag: string; name: string; status: string }
>();
for (const row of rows) {
if (byResource.has(row.resourceId)) continue;
byResource.set(row.resourceId, {
id: row.versionId,
tag: row.tag,
name: row.name,
status: row.status,
});
}
currentByDepResource.set(edge.dependencyDeploymentId, byResource);
}),
);
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

For each dependency edge, this fetches all successful releases across all matching resources and then de-dupes in JS (orderBy(desc(job.completedAt)) + if (byResource.has(...)) continue). This can become expensive for long-lived deployments. Prefer doing the “latest per (resource, environment)” selection in SQL (e.g., DISTINCT ON / window function) and/or fetching for all dependencyDeploymentIds in one query instead of one query per edge.

Suggested change
if (resourceIds.length > 0) {
await Promise.all(
edges.map(async (edge) => {
const rows = await ctx.db
.select({
resourceId: schema.release.resourceId,
versionId: schema.release.versionId,
tag: schema.deploymentVersion.tag,
name: schema.deploymentVersion.name,
status: schema.deploymentVersion.status,
})
.from(schema.release)
.innerJoin(
schema.releaseJob,
eq(schema.releaseJob.releaseId, schema.release.id),
)
.innerJoin(schema.job, eq(schema.job.id, schema.releaseJob.jobId))
.innerJoin(
schema.deploymentVersion,
eq(schema.deploymentVersion.id, schema.release.versionId),
)
.where(
and(
eq(schema.release.deploymentId, edge.dependencyDeploymentId),
inArray(schema.release.resourceId, resourceIds),
eq(schema.job.status, "successful"),
isNotNull(schema.job.completedAt),
),
)
.orderBy(desc(schema.job.completedAt));
const byResource = new Map<
string,
{ id: string; tag: string; name: string; status: string }
>();
for (const row of rows) {
if (byResource.has(row.resourceId)) continue;
byResource.set(row.resourceId, {
id: row.versionId,
tag: row.tag,
name: row.name,
status: row.status,
});
}
currentByDepResource.set(edge.dependencyDeploymentId, byResource);
}),
);
const dependencyDeploymentIds = edges.map(
(edge) => edge.dependencyDeploymentId,
);
if (resourceIds.length > 0 && dependencyDeploymentIds.length > 0) {
const rows = await ctx.db
.select({
deploymentId: schema.release.deploymentId,
resourceId: schema.release.resourceId,
versionId: schema.release.versionId,
tag: schema.deploymentVersion.tag,
name: schema.deploymentVersion.name,
status: schema.deploymentVersion.status,
})
.from(schema.release)
.innerJoin(
schema.releaseJob,
eq(schema.releaseJob.releaseId, schema.release.id),
)
.innerJoin(schema.job, eq(schema.job.id, schema.releaseJob.jobId))
.innerJoin(
schema.deploymentVersion,
eq(schema.deploymentVersion.id, schema.release.versionId),
)
.where(
and(
inArray(schema.release.deploymentId, dependencyDeploymentIds),
inArray(schema.release.resourceId, resourceIds),
eq(schema.job.status, "successful"),
isNotNull(schema.job.completedAt),
),
)
.orderBy(
asc(schema.release.deploymentId),
asc(schema.release.resourceId),
desc(schema.job.completedAt),
);
for (const row of rows) {
let byResource = currentByDepResource.get(row.deploymentId);
if (byResource == null) {
byResource = new Map<
string,
{ id: string; tag: string; name: string; status: string }
>();
currentByDepResource.set(row.deploymentId, byResource);
}
if (byResource.has(row.resourceId)) continue;
byResource.set(row.resourceId, {
id: row.versionId,
tag: row.tag,
name: row.name,
status: row.status,
});
}

Copilot uses AI. Check for mistakes.
.where(
and(
eq(schema.release.deploymentId, edge.dependencyDeploymentId),
eq(schema.release.resourceId, input.resourceId),
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

The upstream release lookup does not filter by input.environmentId, so it can pick a successful dependency release from a different environment for the same resource. Since release is keyed by (resourceId, environmentId, deploymentId), this can cause the UI to mark a dependency satisfied/unsatisfied incorrectly. Include an eq(schema.release.environmentId, input.environmentId) condition (or otherwise ensure you’re selecting the release for the same release-target environment).

Suggested change
eq(schema.release.resourceId, input.resourceId),
eq(schema.release.resourceId, input.resourceId),
eq(schema.release.environmentId, input.environmentId),

Copilot uses AI. Check for mistakes.
Comment on lines +386 to +420
const dependencies = await Promise.all(
edges.map(async (edge) => {
const upstream = await ctx.db
.select({
versionId: schema.release.versionId,
versionTag: schema.deploymentVersion.tag,
versionName: schema.deploymentVersion.name,
versionStatus: schema.deploymentVersion.status,
environmentId: schema.release.environmentId,
completedAt: schema.job.completedAt,
})
.from(schema.release)
.innerJoin(
schema.releaseJob,
eq(schema.releaseJob.releaseId, schema.release.id),
)
.innerJoin(
schema.job,
eq(schema.job.id, schema.releaseJob.jobId),
)
.innerJoin(
schema.deploymentVersion,
eq(schema.deploymentVersion.id, schema.release.versionId),
)
.where(
and(
eq(schema.release.deploymentId, edge.dependencyDeploymentId),
eq(schema.release.resourceId, input.resourceId),
eq(schema.job.status, "successful"),
isNotNull(schema.job.completedAt),
),
)
.orderBy(desc(schema.job.completedAt))
.limit(1);

Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

This performs one SQL query per dependency edge (Promise.all(edges.map(...))). With many dependencies this becomes an N+1 pattern and adds latency. Consider fetching the latest successful release per dependency deployment in a single query (e.g., inArray(release.deploymentId, ...) + grouping / window function / DISTINCT ON) and then mapping results in memory.

Copilot uses AI. Check for mistakes.
Comment on lines +274 to +300
const rows = await ctx.db
.select({
resourceId: schema.release.resourceId,
versionId: schema.release.versionId,
tag: schema.deploymentVersion.tag,
name: schema.deploymentVersion.name,
status: schema.deploymentVersion.status,
})
.from(schema.release)
.innerJoin(
schema.releaseJob,
eq(schema.releaseJob.releaseId, schema.release.id),
)
.innerJoin(schema.job, eq(schema.job.id, schema.releaseJob.jobId))
.innerJoin(
schema.deploymentVersion,
eq(schema.deploymentVersion.id, schema.release.versionId),
)
.where(
and(
eq(schema.release.deploymentId, edge.dependencyDeploymentId),
inArray(schema.release.resourceId, resourceIds),
eq(schema.job.status, "successful"),
isNotNull(schema.job.completedAt),
),
)
.orderBy(desc(schema.job.completedAt));
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

The “current version” lookup ignores release.environmentId entirely and de-duplicates only by resourceId. If the same resource exists in multiple environments, this will attach the latest successful release from an arbitrary environment to all targets for that resource, producing incorrect dependency satisfaction per-environment. Include release.environmentId in the query and key the map by (environmentId, resourceId) (or query per target environment).

Copilot uses AI. Check for mistakes.
Comment on lines +329 to +335
targets: targets.map((t) => ({
resourceId: t.resourceId,
resourceName: t.resourceName,
environmentId: t.environmentId,
environmentName: t.environmentName,
currentVersion: byResource?.get(t.resourceId) ?? null,
})),
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

currentVersion is looked up via byResource?.get(t.resourceId) even though targets are environment-specific. If the same resourceId appears under multiple environments, this will reuse the same current version across environments. Once the upstream query is fixed, use an environment-aware key here as well (e.g., lookup by ${t.environmentId}:${t.resourceId}).

Copilot uses AI. Check for mistakes.
Comment on lines +169 to +184
<button
type="button"
onClick={onToggle}
className="flex w-full items-center gap-2 px-3 py-2 text-left hover:bg-accent"
>
<Caret className="size-3.5 text-muted-foreground" />
<StatusIcon satisfied={dependency.allSatisfied} />
<Link
to={`/${workspaceSlug}/deployments/${dependency.dependencyDeploymentId}`}
target="_blank"
className="text-sm font-medium hover:underline"
onClick={(e) => e.stopPropagation()}
>
{dependency.dependencyDeploymentName ??
dependency.dependencyDeploymentId}
</Link>
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

DependencyGroupHeader renders a <Link> (anchor) inside a <button>, which is invalid HTML and can break keyboard/screen-reader interaction. Refactor so there is only one interactive element (e.g., make the header a non-button container with a separate toggle button, or make the whole row a button and move the link outside).

Copilot uses AI. Check for mistakes.
Comment on lines +292 to +293
{versionLabel} declares {evaluated.length} dependenc
{evaluated.length === 1 ? "y" : "ies"}.{" "}
Copy link

Copilot AI Apr 29, 2026

Choose a reason for hiding this comment

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

Typo in user-facing text: dependenc is missing characters and will render incorrectly. Update the string to dependencies (and keep the pluralization logic intact).

Suggested change
{versionLabel} declares {evaluated.length} dependenc
{evaluated.length === 1 ? "y" : "ies"}.{" "}
{versionLabel} declares {evaluated.length}{" "}
{evaluated.length === 1 ? "dependency" : "dependencies"}.{" "}

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx`:
- Around line 169-184: The header currently nests the Link inside the toggle
<button>, which is invalid and causes focus/keyboard issues; refactor the JSX in
DependencyDetail (the clickable header using onToggle and the <Link> that
navigates to /{workspaceSlug}/deployments/{dependency.dependencyDeploymentId})
so the toggle button and the deployment Link are sibling elements (e.g., wrap
them in a flex container div), keep the toggle button using onToggle and the
StatusIcon/Caret, move the Link out as a separate element that keeps its text
styles and onClick={(e)=>e.stopPropagation()} to avoid triggering the toggle,
and preserve accessibility (type="button" on the toggle) and original
styling/gap behavior.
- Around line 323-326: DependencyDetail currently polls via
trpc.deploymentVersions.dependencies.useQuery({ versionId }, { refetchInterval:
15_000 }) even when its dialog is closed; add local dialog state (const [open,
setOpen] = useState(false)), pass open={open} onOpenChange={setOpen} to the
Dialog component, and gate the query by either using the enabled: open option or
set refetchInterval: open ? 15_000 : false so the background polling only runs
while the dialog is open.

In `@packages/trpc/src/routes/deployment-versions.ts`:
- Around line 267-315: The current cache keys only by resourceId causing
cross-environment bleed; modify the query to select schema.release.environmentId
and restrict results with eq(schema.release.environmentId,
edge.dependencyEnvironmentId), and change the cache shape so
currentByDepResource maps dependencyDeploymentId -> Map<environmentId,
Map<resourceId, {id, tag, name, status}>> (i.e., replace the inner Map<string,
{..}> with a Map<string, Map<string, {..}>>), populate/lookup using both
environmentId and resourceId when building byResource and when setting
currentByDepResource for edge.dependencyDeploymentId so dependency results are
scoped per environment.

In `@packages/trpc/src/routes/release-targets.ts`:
- Around line 388-419: The upstream query is selecting the latest successful
release for the resource across all environments; add an environment filter to
the where clause so only releases from the matching target environment are
considered. Update the and(...) in the query used to build `upstream` (the chain
starting with ctx.db.select(...) and .where(and(...))) to include
eq(schema.release.environmentId, edge.dependencyEnvironmentId) (or the
appropriate target environment identifier if the target env is on `input`), so
the query only returns upstream releases from the same environment as the
dependency.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ad2db75a-82e1-442a-a27b-102196f4a6ac

📥 Commits

Reviewing files that changed from the base of the PR and between c747f21 and 0fea90c.

📒 Files selected for processing (6)
  • apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/DeploymentVersion.tsx
  • apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx
  • apps/web/app/routes/ws/deployments/_components/release-targets/Dependencies.tsx
  • apps/web/app/routes/ws/deployments/page.$deploymentId.release-targets.$releaseTargetKey.tsx
  • packages/trpc/src/routes/deployment-versions.ts
  • packages/trpc/src/routes/release-targets.ts

Comment on lines +323 to +326
const { data, isLoading } = trpc.deploymentVersions.dependencies.useQuery(
{ versionId },
{ refetchInterval: 15_000 },
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect where DependencyDetail is mounted and whether it can fan out across lists of versions.
rg -n -C3 '\bDependencyDetail\b|deploymentVersions\.dependencies\.useQuery' apps/web/app/routes/ws/deployments --iglob '*.tsx'
rg -n -C3 '\bDeploymentVersion\b' apps/web/app/routes/ws/deployments --iglob '*.tsx'

Repository: ctrlplanedev/ctrlplane

Length of output: 9629


🏁 Script executed:

# Read DependencyDetail.tsx to understand the dialog structure and the query at lines 345-357
cat -n apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx | sed -n '300,370p'

Repository: ctrlplanedev/ctrlplane

Length of output: 2077


🏁 Script executed:

# Search for Dialog usage patterns with state management
rg -n -B2 -A5 'useState.*open|Dialog.*open' apps/web/app/routes/ws/deployments --iglob '*.tsx' | head -80

Repository: ctrlplanedev/ctrlplane

Length of output: 5873


🏁 Script executed:

# Get the complete DependencyDetail component
cat -n apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx | head -360

Repository: ctrlplanedev/ctrlplane

Length of output: 11998


Gate the polling interval on the dialog's open state.

Every mounted DependencyDetail polls every 15 seconds regardless of whether its dialog is open. Since DeploymentVersion renders this per visible version, this creates one background query per version row.

Add dialog state management and conditionally enable the query:

  • Track dialog open state with useState
  • Pass open={open} onOpenChange={setOpen} to the <Dialog> component
  • Gate the query with an enabled condition or conditionally set refetchInterval to false when the dialog is closed

This follows the pattern used elsewhere in the codebase for controlled dialogs (e.g., RedeployDialog, VersionActionsPanel).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/web/app/routes/ws/deployments/_components/environmentversiondecisions/rule-results/DependencyDetail.tsx`
around lines 323 - 326, DependencyDetail currently polls via
trpc.deploymentVersions.dependencies.useQuery({ versionId }, { refetchInterval:
15_000 }) even when its dialog is closed; add local dialog state (const [open,
setOpen] = useState(false)), pass open={open} onOpenChange={setOpen} to the
Dialog component, and gate the query by either using the enabled: open option or
set refetchInterval: open ? 15_000 : false so the background polling only runs
while the dialog is open.

Comment thread packages/trpc/src/routes/deployment-versions.ts Outdated
Comment thread packages/trpc/src/routes/release-targets.ts Outdated
@adityachoudhari26 adityachoudhari26 merged commit 392000c into main Apr 29, 2026
9 checks passed
@adityachoudhari26 adityachoudhari26 deleted the deps-ui branch April 29, 2026 21:20
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.

Deployment dependencies: UI surface

2 participants