Fixes critical React crash on the Kanban board view (#830)

* Changes from fix/board-react-crash

* fix: Prevent cascading re-renders and crashes from high-frequency WS events
This commit is contained in:
gsxdsm
2026-03-03 19:23:44 -08:00
committed by GitHub
parent ae48065820
commit dd7108a7a0
9 changed files with 212 additions and 153 deletions

View File

@@ -38,7 +38,6 @@ export function useBoardDragDrop({
// subscribing to the entire store. Bare useAppStore() causes the host component
// (BoardView) to re-render on EVERY store change, which cascades through effects
// and triggers React error #185 (maximum update depth exceeded).
const moveFeature = useAppStore((s) => s.moveFeature);
const updateFeature = useAppStore((s) => s.updateFeature);
// Note: getOrCreateWorktreeForFeature removed - worktrees are now created server-side
@@ -207,7 +206,8 @@ export function useBoardDragDrop({
if (targetStatus === draggedFeature.status) return;
// Handle different drag scenarios
// Note: Worktrees are created server-side at execution time based on feature.branchName
// Note: persistFeatureUpdate handles optimistic RQ cache update internally,
// so no separate moveFeature() call is needed.
if (draggedFeature.status === 'backlog' || draggedFeature.status === 'merge_conflict') {
// From backlog
if (targetStatus === 'in_progress') {
@@ -215,7 +215,6 @@ export function useBoardDragDrop({
// Server will derive workDir from feature.branchName
await handleStartImplementation(draggedFeature);
} else {
moveFeature(featureId, targetStatus);
persistFeatureUpdate(featureId, { status: targetStatus });
}
} else if (draggedFeature.status === 'waiting_approval') {
@@ -223,7 +222,6 @@ export function useBoardDragDrop({
// NOTE: This check must come BEFORE skipTests check because waiting_approval
// features often have skipTests=true, and we want status-based handling first
if (targetStatus === 'verified') {
moveFeature(featureId, 'verified');
// Clear justFinishedAt timestamp when manually verifying via drag
persistFeatureUpdate(featureId, {
status: 'verified',
@@ -237,7 +235,6 @@ export function useBoardDragDrop({
});
} else if (targetStatus === 'backlog') {
// Allow moving waiting_approval cards back to backlog
moveFeature(featureId, 'backlog');
// Clear justFinishedAt timestamp when moving back to backlog
persistFeatureUpdate(featureId, {
status: 'backlog',
@@ -269,7 +266,6 @@ export function useBoardDragDrop({
});
}
}
moveFeature(featureId, 'backlog');
persistFeatureUpdate(featureId, { status: 'backlog' });
toast.info(
isRunningTask
@@ -291,7 +287,6 @@ export function useBoardDragDrop({
return;
} else if (targetStatus === 'verified' && draggedFeature.skipTests) {
// Manual verify via drag (only for skipTests features)
moveFeature(featureId, 'verified');
persistFeatureUpdate(featureId, { status: 'verified' });
toast.success('Feature verified', {
description: `Marked as verified: ${draggedFeature.description.slice(
@@ -304,7 +299,6 @@ export function useBoardDragDrop({
// skipTests feature being moved between verified and waiting_approval
if (targetStatus === 'waiting_approval' && draggedFeature.status === 'verified') {
// Move verified feature back to waiting_approval
moveFeature(featureId, 'waiting_approval');
persistFeatureUpdate(featureId, { status: 'waiting_approval' });
toast.info('Feature moved back', {
description: `Moved back to Waiting Approval: ${draggedFeature.description.slice(
@@ -314,7 +308,6 @@ export function useBoardDragDrop({
});
} else if (targetStatus === 'backlog') {
// Allow moving skipTests cards back to backlog (from verified)
moveFeature(featureId, 'backlog');
persistFeatureUpdate(featureId, { status: 'backlog' });
toast.info('Feature moved to backlog', {
description: `Moved to Backlog: ${draggedFeature.description.slice(
@@ -327,7 +320,6 @@ export function useBoardDragDrop({
// Handle verified TDD (non-skipTests) features being moved back
if (targetStatus === 'waiting_approval') {
// Move verified feature back to waiting_approval
moveFeature(featureId, 'waiting_approval');
persistFeatureUpdate(featureId, { status: 'waiting_approval' });
toast.info('Feature moved back', {
description: `Moved back to Waiting Approval: ${draggedFeature.description.slice(
@@ -337,7 +329,6 @@ export function useBoardDragDrop({
});
} else if (targetStatus === 'backlog') {
// Allow moving verified cards back to backlog
moveFeature(featureId, 'backlog');
persistFeatureUpdate(featureId, { status: 'backlog' });
toast.info('Feature moved to backlog', {
description: `Moved to Backlog: ${draggedFeature.description.slice(
@@ -351,7 +342,6 @@ export function useBoardDragDrop({
[
features,
runningAutoTasks,
moveFeature,
updateFeature,
persistFeatureUpdate,
handleStartImplementation,