Skip to content

fix(desktop): show v1 uncommitted-changes banner instead of second delete prompt#3688

Merged
saddlepaddle merged 1 commit into
mainfrom
galvanized-tv
Apr 23, 2026
Merged

fix(desktop): show v1 uncommitted-changes banner instead of second delete prompt#3688
saddlepaddle merged 1 commit into
mainfrom
galvanized-tv

Conversation

@saddlepaddle
Copy link
Copy Markdown
Collaborator

@saddlepaddle saddlepaddle commented Apr 23, 2026

Summary

  • v2 workspace deletion was warning twice: a generic confirm pane, then a separate "Uncommitted changes in worktree" pane after the destroy hit a conflict
  • Render the v1-style yellow Has uncommitted changes / unpushed commits banner inline on the confirm pane (sourced from electronTrpc.workspaces.canDelete) so the user sees the warning upfront
  • Pass force: true from the confirm when warnings are shown, and silently retry with force on the rare conflict race, so the second prompt is never reached. ConflictPane is removed.

Test plan

  • Delete a workspace with uncommitted changes — yellow banner appears on the confirm pane, single Delete click destroys without a second dialog
  • Delete a workspace with unpushed commits — banner shows "Has unpushed commits", same single-click flow
  • Delete a clean workspace — no banner, normal Delete works
  • Trigger a teardown failure — TeardownFailedPane still shows and "Delete anyway" still forces

Summary by cubic

Show a single inline warning banner for uncommitted changes or unpushed commits on the delete confirm pane and remove the second prompt, keeping workspace deletion a one-click flow with an automatic force retry on conflict races.

  • Bug Fixes
    • Inline v1-style yellow banner on the confirm pane when electronTrpc.workspaces.canDelete reports hasChanges or hasUnpushedCommits; disable Delete while the status is loading.
    • If warnings are shown, pass force: true; on rare conflict races, silently retry with force. Removed the ConflictPane.
    • Kept TeardownFailedPane. Unknown errors now toast only (no dialog). useDestroyDialogState fetches can-delete status on open (5s stale) and exposes hasChanges/hasUnpushedCommits.

Written for commit d31cd51. Summary will update on new commits.

Summary by CodeRabbit

  • Refactor

    • Consolidated deletion UI: warnings about uncommitted changes and unpushed commits now appear inline in the main confirmation dialog; separate conflict and unknown-error panes removed and streamlined.
  • Bug Fixes

    • Deletion flow now checks workspace status, disables confirm while checking, and automatically retries to resolve conflicts without reopening the dialog.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7496ef9c-d8d4-4028-aaa3-2d2eb601fb1b

📥 Commits

Reviewing files that changed from the base of the PR and between b5956c5 and d31cd51.

📒 Files selected for processing (7)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/DashboardSidebarDeleteDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/ConflictPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/DestroyConfirmPane/DestroyConfirmPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/UnknownErrorPane/UnknownErrorPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/UnknownErrorPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts
💤 Files with no reviewable changes (4)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/UnknownErrorPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/ConflictPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/UnknownErrorPane/UnknownErrorPane.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/DestroyConfirmPane/DestroyConfirmPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/DashboardSidebarDeleteDialog.tsx

📝 Walkthrough

Walkthrough

The workspace deletion dialog now runs a preflight workspaces.canDelete check when opened, surfaces any uncommitted/unpushed warnings inline in the confirm pane, removes dedicated Conflict/UnknownError panes, and automatically retries destroy with force: true on conflict errors; only teardown-failed reopens an error pane.

Changes

Cohort / File(s) Summary
ConflictPane Removal
apps/desktop/src/renderer/.../ConflictPane/ConflictPane.tsx, apps/desktop/src/renderer/.../ConflictPane/index.ts
Deleted ConflictPane component and its re-export; no UI for dedicated conflict dialog remains.
UnknownErrorPane Removal
apps/desktop/src/renderer/.../UnknownErrorPane/UnknownErrorPane.tsx, .../UnknownErrorPane/index.ts
Removed UnknownErrorPane component and its re-export; general non-teardown errors are no longer shown via that pane.
Dialog Integration & Hook
apps/desktop/src/renderer/.../DashboardSidebarDeleteDialog/DashboardSidebarDeleteDialog.tsx, .../hooks/useDestroyDialogState/useDestroyDialogState.ts
Hook now accepts open, performs workspaces.canDelete preflight when open, exposes hasChanges, hasUnpushedCommits, isCheckingStatus; retry-on-conflict is automatic (re-run destroy with force: true), clearError removed from hook return. Dialog passes status flags to confirm pane and no longer conditionally renders Conflict/UnknownError panes for non-teardown-failed errors.
Confirm Pane Warning UI
apps/desktop/src/renderer/.../DestroyConfirmPane/DestroyConfirmPane.tsx
Added props hasChanges, hasUnpushedCommits, isCheckingStatus; computes hasWarnings, shows inline yellow warning with context-specific text, disables Delete button while status is checking, and confirm action forwards hasWarnings.

Sequence Diagram

sequenceDiagram
    participant User
    participant Dialog as DashboardSidebarDeleteDialog
    participant Hook as useDestroyDialogState
    participant TRPC as TRPC API
    participant Confirm as DestroyConfirmPane

    User->>Dialog: open dialog
    Dialog->>Hook: init(open=true)
    Hook->>TRPC: query workspaces.canDelete
    TRPC-->>Hook: {hasChanges, hasUnpushedCommits}
    Hook-->>Dialog: expose flags + run()
    Dialog->>Confirm: render(hasChanges, hasUnpushedCommits, isCheckingStatus)
    Confirm->>Confirm: compute hasWarnings, show inline banner if needed
    User->>Confirm: confirm delete
    Confirm->>Hook: run(hasWarnings)
    Hook->>TRPC: mutation destroy(force=false)
    alt conflict & force=false
        TRPC-->>Hook: conflict error
        Hook->>TRPC: mutation destroy(force=true)
        TRPC-->>Hook: success
        Hook-->>Dialog: close
    else teardown-failed
        TRPC-->>Hook: teardown-failed
        Hook-->>Dialog: open error pane
    else success
        TRPC-->>Hook: success
        Hook-->>Dialog: close
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐇 I checked the branches, sniffed the trails,
Waved away the panes that told old tales.
Inline yellow flags now softly say,
“Commits or changes might stay.”
I nudge the destroy, it retries and sails. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% 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
Title check ✅ Passed The title clearly summarizes the main change: replacing a second delete prompt with an inline v1-style banner for uncommitted changes.
Description check ✅ Passed The description includes a clear summary, test plan checklist, and detailed breakdown of changes, addressing the required template sections.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 galvanized-tv

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.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Apr 23, 2026

Greptile Summary

This PR eliminates the double-prompt UX bug when deleting a workspace with uncommitted changes. Instead of showing a generic confirm dialog followed by a separate ConflictPane, the canDelete preflight query now surfaces dirty-worktree state as an inline yellow banner on the confirm pane, and force: true is passed automatically when warnings are present. A silent inner-retry handles the narrow race where the worktree becomes dirty between the preflight and the actual destroy call.

Confidence Score: 5/5

Safe to merge — correctness is preserved by the silent conflict retry, and all remaining findings are P2 suggestions.

No P0/P1 issues found. The two open items are a button label cosmetic (P2) and an optional loading-guard UX improvement (P2); neither affects data integrity or correctness.

No files require special attention.

Important Files Changed

Filename Overview
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts Adds canDelete preflight query (enabled when dialog is open) and silent conflict retry; removes ConflictPane routing — logic is sound with good race handling
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/DashboardSidebarDeleteDialog.tsx Removes ConflictPane dispatch, passes open and warning flags through; run(hasWarnings) correctly passes force: true when dirty state is known
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/DestroyConfirmPane/DestroyConfirmPane.tsx Adds yellow inline warning banner for dirty/unpushed state; Delete button label unchanged despite warnings being shown — minor UX inconsistency
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/ConflictPane.tsx File deleted — ConflictPane is fully superseded by the inline banner approach
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/index.ts Barrel export deleted along with ConflictPane

Sequence Diagram

sequenceDiagram
    participant U as User
    participant D as DeleteDialog
    participant Q as canDelete query
    participant W as destroy (IPC)

    U->>D: Click "Delete workspace"
    D->>Q: useQuery({ enabled: true })
    Q-->>D: { hasChanges, hasUnpushedCommits }
    Note over D: Show yellow banner if dirty
    U->>D: Click "Delete" (force = hasWarnings)
    D->>W: destroy({ force })
    alt worktree clean OR force=true
        W-->>D: DestroyWorkspaceSuccess
        D->>U: toast warnings (if any)
    else conflict race (force=false, dirty)
        W-->>D: conflict error
        D->>W: destroy({ force: true }) [silent retry]
        W-->>D: DestroyWorkspaceSuccess
    else teardown-failed
        W-->>D: teardown-failed error
        D->>U: Reopen dialog → TeardownFailedPane
    end
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/DestroyConfirmPane/DestroyConfirmPane.tsx, line 86-91 (link)

    P2 Button label unchanged when warnings are shown

    When the yellow banner is visible, the "Delete" button label doesn't update to reflect that the user is overriding the warning. Without a label change (e.g. "Delete anyway"), it's easy to miss that clicking Delete will discard uncommitted changes.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/DestroyConfirmPane/DestroyConfirmPane.tsx
    Line: 86-91
    
    Comment:
    **Button label unchanged when warnings are shown**
    
    When the yellow banner is visible, the "Delete" button label doesn't update to reflect that the user is overriding the warning. Without a label change (e.g. "Delete anyway"), it's easy to miss that clicking Delete will discard uncommitted changes.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/DestroyConfirmPane/DestroyConfirmPane.tsx
Line: 86-91

Comment:
**Button label unchanged when warnings are shown**

When the yellow banner is visible, the "Delete" button label doesn't update to reflect that the user is overriding the warning. Without a label change (e.g. "Delete anyway"), it's easy to miss that clicking Delete will discard uncommitted changes.

```suggestion
Delete{hasWarnings ? " anyway" : ""}
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts
Line: 34-43

Comment:
**No pending/loading guard while `canDelete` query resolves**

`hasChanges` and `hasUnpushedCommits` both default to `false` while the query is in-flight. On a slow IPC call the banner never renders before the user clicks Delete — they skip the warning entirely. The silent conflict-retry means correctness is preserved, but if this latency is common, consider using the `isPending` / `isLoading` flag from the query result to disable the Delete button (or show a spinner) until the status is confirmed.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(desktop): show v1 uncommitted-change..." | Re-trigger Greptile

Comment on lines +34 to +43
{ id: workspaceId },
{
enabled: open,
staleTime: STATUS_STALE_TIME_MS,
refetchOnWindowFocus: false,
},
);
const hasChanges = canDeleteData?.hasChanges ?? false;
const hasUnpushedCommits = canDeleteData?.hasUnpushedCommits ?? false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 No pending/loading guard while canDelete query resolves

hasChanges and hasUnpushedCommits both default to false while the query is in-flight. On a slow IPC call the banner never renders before the user clicks Delete — they skip the warning entirely. The silent conflict-retry means correctness is preserved, but if this latency is common, consider using the isPending / isLoading flag from the query result to disable the Delete button (or show a spinner) until the status is confirmed.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts
Line: 34-43

Comment:
**No pending/loading guard while `canDelete` query resolves**

`hasChanges` and `hasUnpushedCommits` both default to `false` while the query is in-flight. On a slow IPC call the banner never renders before the user clicks Delete — they skip the warning entirely. The silent conflict-retry means correctness is preserved, but if this latency is common, consider using the `isPending` / `isLoading` flag from the query result to disable the Delete button (or show a spinner) until the status is confirmed.

How can I resolve this? If you propose a fix, please make it concise.

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.

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts (1)

93-100: ⚠️ Potential issue | 🟡 Minor

Narrowing setError to only teardown-failed leaves UnknownErrorPane unreachable.

DashboardSidebarDeleteDialog.tsx still renders UnknownErrorPane when error?.kind === "unknown" (lines 56–65), but this branch now only calls setError for teardown-failed. An unknown error only produces a toast, so error.kind can never be "unknown" and that pane is dead code.

Either keep surfacing unknown errors via the pane, or drop the pane + its import in the parent. Preferring the latter matches the intent described in the PR (teardown failures still surface TeardownFailedPane; everything else toasts), but make it explicit so the UI isn't carrying an unreachable branch.

♻️ Option A — keep UnknownErrorPane reachable
-				if (e.kind === "teardown-failed") {
+				if (e.kind === "teardown-failed" || e.kind === "unknown") {
 					setError(e);
 					onOpenChange(true);
 				} else {
 					toast.error(`Failed to delete ${workspaceName}: ${e.message}`);
 				}
♻️ Option B — drop the unreachable pane in the parent

In DashboardSidebarDeleteDialog.tsx:

-import { UnknownErrorPane } from "./components/UnknownErrorPane";
 ...
-	if (error?.kind === "unknown") {
-		return (
-			<UnknownErrorPane
-				open={open}
-				onOpenChange={handleOpenChange}
-				message={error.message}
-				onRetry={clearError}
-			/>
-		);
-	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts`
around lines 93 - 100, The current catch narrows setError to only
teardown-failed, making UnknownErrorPane in DashboardSidebarDeleteDialog.tsx
unreachable; remove the unused UnknownErrorPane import and its JSX branch (the
conditional that checks error?.kind === "unknown") from
DashboardSidebarDeleteDialog.tsx so the UI matches the handler in
useDestroyDialogState (keep TeardownFailedPane and the toast behavior for other
errors), and verify there are no leftover references to UnknownErrorPane or its
prop usage.
🤖 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/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts`:
- Around line 93-100: The current catch narrows setError to only
teardown-failed, making UnknownErrorPane in DashboardSidebarDeleteDialog.tsx
unreachable; remove the unused UnknownErrorPane import and its JSX branch (the
conditional that checks error?.kind === "unknown") from
DashboardSidebarDeleteDialog.tsx so the UI matches the handler in
useDestroyDialogState (keep TeardownFailedPane and the toast behavior for other
errors), and verify there are no leftover references to UnknownErrorPane or its
prop usage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ce2a836-8105-4fc4-8b3d-bc1fce35509c

📥 Commits

Reviewing files that changed from the base of the PR and between 8b3ff23 and b5956c5.

📒 Files selected for processing (5)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/DashboardSidebarDeleteDialog.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/ConflictPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/DestroyConfirmPane/DestroyConfirmPane.tsx
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts
💤 Files with no reviewable changes (2)
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/index.ts
  • apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/components/ConflictPane/ConflictPane.tsx

Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 5 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts">

<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarDeleteDialog/hooks/useDestroyDialogState/useDestroyDialogState.ts:41">
P2: While the `canDelete` query is in-flight, `hasChanges` and `hasUnpushedCommits` default to `false`, so the warning banner won't render and `run(false)` is called on confirm. On a slow IPC call the user can delete without ever seeing the dirty-worktree warning. Consider destructuring `isPending` from the query and disabling the Delete button (or passing a loading state) until the status is confirmed.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

…lete prompt

The v2 workspace delete flow showed two warnings: a generic confirm pane,
then a "Uncommitted changes in worktree" pane after destroy hit a conflict.
Surface the v1 yellow banner inline on the confirm pane via the existing
canDelete preflight, force when warnings are shown, and silently retry on
the rare race so the user only ever sees one prompt.
@saddlepaddle saddlepaddle merged commit 4f62bd3 into main Apr 23, 2026
6 checks passed
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch

Thank you for your contribution! 🎉

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.

1 participant