mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-02 20:43:36 +00:00
- Introduced a new IdeationService to manage brainstorming sessions, including idea creation, analysis, and conversion to features. - Added RESTful API routes for ideation, including session management, idea CRUD operations, and suggestion generation. - Created UI components for the ideation dashboard, prompt selection, and category grid to enhance user experience. - Integrated keyboard shortcuts and navigation for the ideation feature, improving accessibility and workflow. - Updated state management with Zustand to handle ideation-specific data and actions. - Added necessary types and paths for ideation functionality, ensuring type safety and clarity in the codebase.
157 lines
4.7 KiB
TypeScript
157 lines
4.7 KiB
TypeScript
import { useEffect, useRef } from 'react';
|
|
import { getElectronAPI } from '@/lib/electron';
|
|
import { useAppStore } from '@/store/app-store';
|
|
|
|
interface UseBoardEffectsProps {
|
|
currentProject: { path: string; id: string } | null;
|
|
specCreatingForProject: string | null;
|
|
setSpecCreatingForProject: (path: string | null) => void;
|
|
checkContextExists: (featureId: string) => Promise<boolean>;
|
|
features: any[];
|
|
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 as any).__currentProject = currentProject;
|
|
}
|
|
return () => {
|
|
(window as any).__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) => {
|
|
console.log(
|
|
'[BoardView] 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]);
|
|
|
|
// Sync running tasks from electron backend on mount
|
|
useEffect(() => {
|
|
if (!currentProject) return;
|
|
|
|
const syncRunningTasks = async () => {
|
|
try {
|
|
const api = getElectronAPI();
|
|
if (!api?.autoMode?.status) return;
|
|
|
|
const status = await api.autoMode.status(currentProject.path);
|
|
if (status.success) {
|
|
const projectId = currentProject.id;
|
|
const { clearRunningTasks, addRunningTask } = useAppStore.getState();
|
|
|
|
if (status.runningFeatures) {
|
|
console.log('[Board] Syncing running tasks from backend:', status.runningFeatures);
|
|
|
|
clearRunningTasks(projectId);
|
|
|
|
status.runningFeatures.forEach((featureId: string) => {
|
|
addRunningTask(projectId, featureId);
|
|
});
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('[Board] Failed to sync running tasks:', error);
|
|
}
|
|
};
|
|
|
|
syncRunningTasks();
|
|
}, [currentProject]);
|
|
|
|
// 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'
|
|
);
|
|
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]);
|
|
}
|