mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-31 06:42:03 +00:00
Add a new interactive graph view alongside the kanban board for visualizing task dependencies. The graph view uses React Flow with dagre auto-layout to display tasks as nodes connected by dependency edges. Key features: - Toggle between kanban and graph view via new control buttons - Custom TaskNode component matching existing card styling/themes - Animated edges that flow when tasks are in progress - Status-aware node colors (backlog, in-progress, waiting, verified) - Blocked tasks show lock icon with dependency count tooltip - MiniMap for navigation in large graphs - Zoom, pan, fit-view, and lock controls - Horizontal/vertical layout options via dagre - Click node to view details, double-click to edit - Respects all 32 themes via CSS variables - Reduced motion support for animations New dependencies: @xyflow/react, dagre
90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
import { useMemo, useCallback } from 'react';
|
|
import { Feature, useAppStore } from '@/store/app-store';
|
|
import { GraphCanvas } from './graph-canvas';
|
|
import { useBoardBackground } from '../board-view/hooks';
|
|
|
|
interface GraphViewProps {
|
|
features: Feature[];
|
|
runningAutoTasks: string[];
|
|
currentWorktreePath: string | null;
|
|
currentWorktreeBranch: string | null;
|
|
projectPath: string | null;
|
|
onEditFeature: (feature: Feature) => void;
|
|
onViewOutput: (feature: Feature) => void;
|
|
}
|
|
|
|
export function GraphView({
|
|
features,
|
|
runningAutoTasks,
|
|
currentWorktreePath,
|
|
currentWorktreeBranch,
|
|
projectPath,
|
|
onEditFeature,
|
|
onViewOutput,
|
|
}: GraphViewProps) {
|
|
const { currentProject } = useAppStore();
|
|
|
|
// Use the same background hook as the board view
|
|
const { backgroundImageStyle } = useBoardBackground({ currentProject });
|
|
|
|
// Filter features by current worktree (same logic as board view)
|
|
const filteredFeatures = useMemo(() => {
|
|
const effectiveBranch = currentWorktreeBranch;
|
|
|
|
return features.filter((f) => {
|
|
// Skip completed features (they're in archive)
|
|
if (f.status === 'completed') return false;
|
|
|
|
const featureBranch = f.branchName;
|
|
|
|
if (!featureBranch) {
|
|
// No branch assigned - show only on primary worktree
|
|
return currentWorktreePath === null;
|
|
} else if (effectiveBranch === null) {
|
|
// Viewing main but branch not initialized
|
|
return projectPath
|
|
? useAppStore.getState().isPrimaryWorktreeBranch(projectPath, featureBranch)
|
|
: false;
|
|
} else {
|
|
// Match by branch name
|
|
return featureBranch === effectiveBranch;
|
|
}
|
|
});
|
|
}, [features, currentWorktreePath, currentWorktreeBranch, projectPath]);
|
|
|
|
// Handle node click - view details
|
|
const handleNodeClick = useCallback(
|
|
(featureId: string) => {
|
|
const feature = features.find((f) => f.id === featureId);
|
|
if (feature) {
|
|
onViewOutput(feature);
|
|
}
|
|
},
|
|
[features, onViewOutput]
|
|
);
|
|
|
|
// Handle node double click - edit
|
|
const handleNodeDoubleClick = useCallback(
|
|
(featureId: string) => {
|
|
const feature = features.find((f) => f.id === featureId);
|
|
if (feature) {
|
|
onEditFeature(feature);
|
|
}
|
|
},
|
|
[features, onEditFeature]
|
|
);
|
|
|
|
return (
|
|
<div className="flex-1 overflow-hidden relative">
|
|
<GraphCanvas
|
|
features={filteredFeatures}
|
|
runningAutoTasks={runningAutoTasks}
|
|
onNodeClick={handleNodeClick}
|
|
onNodeDoubleClick={handleNodeDoubleClick}
|
|
backgroundStyle={backgroundImageStyle}
|
|
className="h-full"
|
|
/>
|
|
</div>
|
|
);
|
|
}
|