diff --git a/apps/server/src/routes/features/routes/bulk-delete.ts b/apps/server/src/routes/features/routes/bulk-delete.ts index 6966d69a..555515ae 100644 --- a/apps/server/src/routes/features/routes/bulk-delete.ts +++ b/apps/server/src/routes/features/routes/bulk-delete.ts @@ -30,23 +30,22 @@ export function createBulkDeleteHandler(featureLoader: FeatureLoader) { return; } - const results: BulkDeleteResult[] = []; - - for (const featureId of featureIds) { - try { + const results = await Promise.all( + featureIds.map(async (featureId) => { const success = await featureLoader.delete(projectPath, featureId); - results.push({ featureId, success }); - } catch (error) { - results.push({ + if (success) { + return { featureId, success: true }; + } + return { featureId, success: false, - error: getErrorMessage(error), - }); - } - } + error: 'Deletion failed. Check server logs for details.', + }; + }) + ); - const successCount = results.filter((r) => r.success).length; - const failureCount = results.filter((r) => !r.success).length; + const successCount = results.reduce((count, r) => count + (r.success ? 1 : 0), 0); + const failureCount = results.length - successCount; res.json({ success: failureCount === 0, diff --git a/apps/ui/src/components/views/board-view.tsx b/apps/ui/src/components/views/board-view.tsx index 3aa2e47a..2b1e3591 100644 --- a/apps/ui/src/components/views/board-view.tsx +++ b/apps/ui/src/components/views/board-view.tsx @@ -514,24 +514,35 @@ export function BoardView() { const featureIds = Array.from(selectedFeatureIds); const result = await api.features.bulkDelete(currentProject.path, featureIds); - if (result.success) { - // Delete from local state - featureIds.forEach((featureId) => { - persistFeatureDelete(featureId); + const successfullyDeletedIds = + result.results?.filter((r) => r.success).map((r) => r.featureId) ?? []; + + if (successfullyDeletedIds.length > 0) { + // Delete from local state without calling the API again + successfullyDeletedIds.forEach((featureId) => { + useAppStore.getState().removeFeature(featureId); }); - toast.success(`Deleted ${result.deletedCount} features`); - exitSelectionMode(); - loadFeatures(); - } else { + toast.success(`Deleted ${successfullyDeletedIds.length} features`); + } + + if (result.failedCount && result.failedCount > 0) { toast.error('Failed to delete some features', { description: `${result.failedCount} features failed to delete`, }); } + + // Exit selection mode and reload if the operation was at least partially processed. + if (result.results) { + exitSelectionMode(); + loadFeatures(); + } else if (!result.success) { + toast.error('Failed to delete features', { description: result.error }); + } } catch (error) { logger.error('Bulk delete failed:', error); toast.error('Failed to delete features'); } - }, [currentProject, selectedFeatureIds, persistFeatureDelete, exitSelectionMode, loadFeatures]); + }, [currentProject, selectedFeatureIds, exitSelectionMode, loadFeatures]); // Get selected features for mass edit dialog const selectedFeatures = useMemo(() => {