Files
automaker/apps/ui/src/components/views/board-view/hooks/use-board-effects.ts
Shirone 0fb471ca15 chore: Enhance type safety and improve code consistency across components
- Added a new `typecheck` script in `package.json` for better type checking in the UI workspace.
- Refactored several components to remove unnecessary type assertions and improve type safety, particularly in `new-project-modal.tsx`, `edit-project-dialog.tsx`, and `task-progress-panel.tsx`.
- Updated event handling in `git-diff-panel.tsx` to use async functions for better error handling.
- Improved type definitions in various files, including `setup-view` and `electron.ts`, to ensure consistent usage of types across the codebase.
- Cleaned up global type definitions for better clarity and maintainability.

These changes aim to streamline the development process and reduce potential runtime errors.
2026-01-25 18:11:48 +01:00

129 lines
4.0 KiB
TypeScript

import { useEffect, useRef } from 'react';
import { getElectronAPI } from '@/lib/electron';
import { createLogger } from '@automaker/utils/logger';
import type { Feature } from '@/store/app-store';
const logger = createLogger('BoardEffects');
interface UseBoardEffectsProps {
currentProject: { path: string; id: string; name?: string } | null;
specCreatingForProject: string | null;
setSpecCreatingForProject: (path: string | null) => void;
checkContextExists: (featureId: string) => Promise<boolean>;
features: Feature[];
isLoading: boolean;
featuresWithContext: Set<string>;
setFeaturesWithContext: (set: Set<string>) => void;
}
export function useBoardEffects({
currentProject,
specCreatingForProject,
setSpecCreatingForProject,
checkContextExists,
features,
isLoading,
featuresWithContext,
setFeaturesWithContext,
}: UseBoardEffectsProps) {
// Keep a ref to the current featuresWithContext for use in event handlers
const featuresWithContextRef = useRef(featuresWithContext);
useEffect(() => {
featuresWithContextRef.current = featuresWithContext;
}, [featuresWithContext]);
// Make current project available globally for modal
useEffect(() => {
if (currentProject) {
window.__currentProject = currentProject;
}
return () => {
window.__currentProject = null;
};
}, [currentProject]);
// Subscribe to spec regeneration events to clear creating state on completion
useEffect(() => {
const api = getElectronAPI();
if (!api.specRegeneration) return;
const unsubscribe = api.specRegeneration.onEvent((event) => {
logger.info('Spec regeneration event:', event.type, 'for project:', event.projectPath);
if (event.projectPath !== specCreatingForProject) {
return;
}
if (event.type === 'spec_regeneration_complete') {
setSpecCreatingForProject(null);
} else if (event.type === 'spec_regeneration_error') {
setSpecCreatingForProject(null);
}
});
return () => {
unsubscribe();
};
}, [specCreatingForProject, setSpecCreatingForProject]);
// Note: Running tasks sync is now handled by useAutoMode hook in BoardView
// which correctly handles worktree/branch scoping.
// Check which features have context files
useEffect(() => {
const checkAllContexts = async () => {
const featuresWithPotentialContext = features.filter(
(f) =>
f.status === 'in_progress' ||
f.status === 'waiting_approval' ||
f.status === 'verified' ||
(typeof f.status === 'string' && f.status.startsWith('pipeline_'))
);
const contextChecks = await Promise.all(
featuresWithPotentialContext.map(async (f) => ({
id: f.id,
hasContext: await checkContextExists(f.id),
}))
);
const newSet = new Set<string>();
contextChecks.forEach(({ id, hasContext }) => {
if (hasContext) {
newSet.add(id);
}
});
setFeaturesWithContext(newSet);
};
if (features.length > 0 && !isLoading) {
checkAllContexts();
}
}, [features, isLoading, checkContextExists, setFeaturesWithContext]);
// Re-check context when a feature stops, completes, or errors
// This ensures hasContext is updated even if the features array doesn't change
useEffect(() => {
const api = getElectronAPI();
if (!api?.autoMode) return;
const unsubscribe = api.autoMode.onEvent(async (event) => {
// When a feature stops (error/abort) or completes, re-check its context
if (
(event.type === 'auto_mode_error' || event.type === 'auto_mode_feature_complete') &&
event.featureId
) {
const hasContext = await checkContextExists(event.featureId);
if (hasContext) {
const newSet = new Set(featuresWithContextRef.current);
newSet.add(event.featureId);
setFeaturesWithContext(newSet);
}
}
});
return () => {
unsubscribe();
};
}, [checkContextExists, setFeaturesWithContext]);
}