feat(stacks): add optional volume prune to delete confirmation (#788)

The Delete Stack dialog now includes an opt-in checkbox to also remove
associated Docker volumes when the stack is deleted. The checkbox is
unchecked by default and resets to unchecked on every open.

Backend: DELETE /stacks/:name accepts ?pruneVolumes=true and calls
pruneManagedOnly for volumes labeled with the stack project name after
bringing the stack down. Prune failure is non-fatal and logged; the
delete proceeds regardless.
This commit is contained in:
Anso
2026-04-26 18:56:30 -04:00
committed by GitHub
parent dcf8794047
commit 38a9f277c6
2 changed files with 28 additions and 2 deletions
+10
View File
@@ -526,6 +526,7 @@ stacksRouter.delete('/:stackName', async (req: Request, res: Response) => {
if (!isValidStackName(stackName)) {
return res.status(400).json({ error: 'Invalid stack name' });
}
const pruneVolumes = req.query.pruneVolumes === 'true';
try {
try {
await ComposeService.getInstance(req.nodeId).downStack(stackName);
@@ -533,6 +534,15 @@ stacksRouter.delete('/:stackName', async (req: Request, res: Response) => {
console.warn(`[Teardown] Docker down failed or nothing to clean up for ${stackName}`);
}
if (pruneVolumes) {
try {
const result = await DockerController.getInstance().pruneManagedOnly('volumes', [stackName]);
console.log(`[Stacks] Pruned volumes for ${stackName}: ${result.reclaimedBytes} bytes reclaimed`);
} catch (pruneErr) {
console.warn(`[Stacks] Volume prune failed for ${stackName}, continuing delete:`, pruneErr);
}
}
let fsErr: unknown = null;
try {
await FileSystemService.getInstance(req.nodeId).deleteStack(stackName);