Skip to content

fix: allow updating status of deployment versions with no jobs - #989

Closed
adityachoudhari26 wants to merge 1 commit into
mainfrom
claude/issue-988-20260414-1849
Closed

adityachoudhari26 wants to merge 1 commit into
mainfrom
claude/issue-988-20260414-1849

Conversation

@adityachoudhari26

@adityachoudhari26 adityachoudhari26 commented Apr 14, 2026 •

Copy link
Copy Markdown
Member

Fixes two related bugs where users could not update the status of a deployment version that has no jobs:

  1. Dialog closes immediately: VersionStatusDialog was nested inside DropdownMenuContent as an uncontrolled Radix Dialog. When the Dialog overlay appeared, Radix's DismissableLayer fired onOpenChange(false) on the parent DropdownMenu, unmounting DropdownMenuContent and the Dialog with it. Fixed by converting to a controlled Dialog with state lifted outside the dropdown.

  2. No Update Status option for zero-job versions: NoActiveDeployments didn't render VersionDropdown, so there was no way to trigger "Update Status" for versions with no active deployments. Fixed by adding VersionDropdown to the component.

Closes #988

Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Version dropdown menu now available in the no active deployments state.
  • Refactor

    • Improved dialog state management for smoother version status update interactions.

- Lift VersionStatusDialog state outside DropdownMenu in VersionDropdown
  so the status dialog doesn't unmount when the dropdown closes (Radix
  DismissableLayer was firing onOpenChange(false) on the DropdownMenu
  when the Dialog overlay appeared, unmounting the Dialog along with the
  DropdownMenuContent)
- Add VersionDropdown to NoActiveDeployments so versions with no active
  jobs also expose the "Update Status" action

Fixes #988

Co-authored-by: Aditya Choudhari <adityachoudhari26@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 14, 2026 20:17
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai

coderabbitai Bot commented Apr 14, 2026 •

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Added VersionDropdown rendering to the NoActiveDeployments card in VersionCard. Refactored VersionStatusDialog from an uncontrolled component with DialogTrigger to a controlled component using open/onOpenChange props. Separated dropdown menu and status dialog state in VersionDropdown to prevent unintended modal closure.

Changes

Cohort / File(s) Summary
Version Card Enhancement
apps/web/app/routes/ws/deployments/_components/versioncard/VersionCard.tsx
Added VersionDropdown component rendering in NoActiveDeployments section to provide status update functionality.
Dialog State Management Refactoring
apps/web/app/routes/ws/deployments/_components/versioncard/VersionDropdown.tsx
Converted VersionStatusDialog to controlled component pattern with open/onOpenChange props. Split single open state into separate dropdownOpen and statusDialogOpen states. Updated "Update Status" selection to prevent default behavior, close dropdown, and open dialog independently.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Suggested reviewers

  • jsbroks

Poem

🐰 A modal that wouldn't stay still,
Now opens with independent will,
Dropdown and dialog, no longer entwined,
State separation—such peace we find! ✨
The version update hops on through,
No jobs? No problem—we've got the fix for you!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

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.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main fix: allowing users to update deployment version status for versions with no jobs, which is the core objective.
Linked Issues check ✅ Passed The PR successfully addresses both requirements from issue #988: fixing the dialog closing issue via controlled state management and adding VersionDropdown to NoActiveDeployments.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the status update functionality for zero-job versions; no unrelated or out-of-scope modifications detected.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/issue-988-20260414-1849

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.

Copilot AI left a comment

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.

Pull request overview

This PR fixes UI/UX issues preventing users from updating a deployment version’s status when the version has no jobs, primarily by preventing Radix dropdown unmounting from immediately closing the status dialog and by surfacing the status action for zero-active-deployment versions.

Changes:

  • Refactors VersionStatusDialog to a controlled Dialog with open state lifted out of DropdownMenuContent to avoid immediate dismissal/unmounting.
  • Adds VersionDropdown to the “no active deployments” version card state so “Update Status” remains reachable.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
apps/web/app/routes/ws/deployments/_components/versioncard/VersionDropdown.tsx Converts the dialog to controlled state and decouples it from the dropdown content to prevent auto-close/unmount behavior.
apps/web/app/routes/ws/deployments/_components/versioncard/VersionCard.tsx Renders the version actions dropdown even when there are no active deployments for the version.

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

Comment on lines 67 to +68
const [status, setStatus] = useState<VersionStatus>(version.status);
const onClick = () => updateStatus(status).then(onClose);
const onClick = () => updateStatus(status).then(() => onOpenChange(false));
const { updateStatus, isPending } = useUpdateVersionStatus(version.id);
const [status, setStatus] = useState<VersionStatus>(version.status);
const onClick = () => updateStatus(status).then(onClose);
const onClick = () => updateStatus(status).then(() => onOpenChange(false));
Comment on lines +116 to +123
<Button
variant="ghost"
size="icon"
className="h-7 w-7 shrink-0 text-muted-foreground"
onClick={(e) => e.stopPropagation()}
>
<EllipsisIcon className="size-3" />
</Button>
Comment on lines 66 to +68
const { updateStatus, isPending } = useUpdateVersionStatus(version.id);
const [status, setStatus] = useState<VersionStatus>(version.status);
const onClick = () => updateStatus(status).then(onClose);
const onClick = () => updateStatus(status).then(() => onOpenChange(false));

@coderabbitai coderabbitai Bot left a comment

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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/web/app/routes/ws/deployments/_components/versioncard/VersionDropdown.tsx (1)

48-52: ⚠️ Potential issue | 🟡 Minor

Add error handling for failed status updates.

If the mutation fails, the user receives no feedback. Consider adding a .catch() handler to show an error toast.

🛡️ Proposed fix to add error handling
   const updateStatus = (status: VersionStatus) =>
     updateVersionStatus
       .mutateAsync({ workspaceId, versionId, status })
       .then(() => toast.success("Status update queued successfully"))
-      .then(() => invalidateVersions());
+      .then(() => invalidateVersions())
+      .catch((error) => {
+        toast.error("Failed to update status");
+        throw error;
+      });
🤖 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/versioncard/VersionDropdown.tsx`
around lines 48 - 52, The updateStatus function currently chains
updateVersionStatus.mutateAsync(...).then(...).then(...) without handling
failures; add a .catch() to that promise chain (after invalidateVersions()) to
call toast.error with a helpful message and optionally log the error so the user
is notified when the mutation fails; reference updateStatus and
updateVersionStatus.mutateAsync and ensure invalidateVersions() still runs only
on success while the .catch handles errors from mutateAsync and the subsequent
thens.
🧹 Nitpick comments (1)
apps/web/app/routes/ws/deployments/_components/versioncard/VersionDropdown.tsx (1)

67-68: Consider resetting status state when the dialog opens.

The status state is initialized from version.status only on mount. If the version's status is updated externally (e.g., by another user) and the dialog is reopened without the component remounting, the Select will show the stale initial value rather than the current version.status.

♻️ Proposed fix using useEffect to sync state
+import { useState, useEffect } from "react";
...
 function VersionStatusDialog({
   version,
   open,
   onOpenChange,
 }: {
   version: Version;
   open: boolean;
   onOpenChange: (open: boolean) => void;
 }) {
   const { updateStatus, isPending } = useUpdateVersionStatus(version.id);
   const [status, setStatus] = useState<VersionStatus>(version.status);
+  
+  useEffect(() => {
+    if (open) {
+      setStatus(version.status);
+    }
+  }, [open, version.status]);
+
   const onClick = () => updateStatus(status).then(() => onOpenChange(false));
🤖 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/versioncard/VersionDropdown.tsx`
around lines 67 - 68, The local status state (status, setStatus typed as
VersionStatus) is only initialized from version.status on mount and can become
stale if the dialog is reopened; add a useEffect that resets
setStatus(version.status) whenever the dialog is opened (watch version.status
and the dialog open flag/prop) so the Select shows the current version.status
when the dialog opens, leaving onClick
(updateStatus(...).then(()=>onOpenChange(false))) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@apps/web/app/routes/ws/deployments/_components/versioncard/VersionDropdown.tsx`:
- Around line 48-52: The updateStatus function currently chains
updateVersionStatus.mutateAsync(...).then(...).then(...) without handling
failures; add a .catch() to that promise chain (after invalidateVersions()) to
call toast.error with a helpful message and optionally log the error so the user
is notified when the mutation fails; reference updateStatus and
updateVersionStatus.mutateAsync and ensure invalidateVersions() still runs only
on success while the .catch handles errors from mutateAsync and the subsequent
thens.

---

Nitpick comments:
In
`@apps/web/app/routes/ws/deployments/_components/versioncard/VersionDropdown.tsx`:
- Around line 67-68: The local status state (status, setStatus typed as
VersionStatus) is only initialized from version.status on mount and can become
stale if the dialog is reopened; add a useEffect that resets
setStatus(version.status) whenever the dialog is opened (watch version.status
and the dialog open flag/prop) so the Select shows the current version.status
when the dialog opens, leaving onClick
(updateStatus(...).then(()=>onOpenChange(false))) unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b2cfa337-07f6-451a-9495-3ddf6048b206

📥 Commits

Reviewing files that changed from the base of the PR and between 230baf4 and 1647658.

📒 Files selected for processing (2)
  • apps/web/app/routes/ws/deployments/_components/versioncard/VersionCard.tsx
  • apps/web/app/routes/ws/deployments/_components/versioncard/VersionDropdown.tsx

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.

bug: unable to update status of dep version that has no jobs

3 participants