adding button to make when creating a new feature

This commit is contained in:
Test User
2025-12-27 13:55:56 -05:00
parent b60e8f0392
commit 7b7de2b601
2 changed files with 88 additions and 23 deletions

View File

@@ -523,6 +523,29 @@ export function BoardView() {
[handleAddFeature, handleStartImplementation, defaultSkipTests] [handleAddFeature, handleStartImplementation, defaultSkipTests]
); );
// Handler for "Make" button - creates a feature and immediately starts it
const handleAddAndStartFeature = useCallback(
async (featureData: Parameters<typeof handleAddFeature>[0]) => {
await handleAddFeature(featureData);
// Find the newly created feature and start it
setTimeout(async () => {
const latestFeatures = useAppStore.getState().features;
const newFeature = latestFeatures.find(
(f) =>
f.status === 'backlog' &&
f.description === featureData.description &&
f.branchName === featureData.branchName
);
if (newFeature) {
await handleStartImplementation(newFeature);
}
}, FEATURE_CREATION_SETTLE_DELAY_MS);
},
[handleAddFeature, handleStartImplementation]
);
// Client-side auto mode: periodically check for backlog items and move them to in-progress // Client-side auto mode: periodically check for backlog items and move them to in-progress
// Use a ref to track the latest auto mode state so async operations always check the current value // Use a ref to track the latest auto mode state so async operations always check the current value
const autoModeRunningRef = useRef(autoMode.isRunning); const autoModeRunningRef = useRef(autoMode.isRunning);
@@ -1137,6 +1160,7 @@ export function BoardView() {
} }
}} }}
onAdd={handleAddFeature} onAdd={handleAddFeature}
onAddAndStart={handleAddAndStartFeature}
categorySuggestions={categorySuggestions} categorySuggestions={categorySuggestions}
branchSuggestions={branchSuggestions} branchSuggestions={branchSuggestions}
branchCardCounts={branchCardCounts} branchCardCounts={branchCardCounts}

View File

@@ -19,7 +19,14 @@ import {
FeatureTextFilePath as DescriptionTextFilePath, FeatureTextFilePath as DescriptionTextFilePath,
ImagePreviewMap, ImagePreviewMap,
} from '@/components/ui/description-image-dropzone'; } from '@/components/ui/description-image-dropzone';
import { MessageSquare, Settings2, SlidersHorizontal, Sparkles, ChevronDown } from 'lucide-react'; import {
MessageSquare,
Settings2,
SlidersHorizontal,
Sparkles,
ChevronDown,
Play,
} from 'lucide-react';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { getElectronAPI } from '@/lib/electron'; import { getElectronAPI } from '@/lib/electron';
import { modelSupportsThinking } from '@/lib/utils'; import { modelSupportsThinking } from '@/lib/utils';
@@ -55,25 +62,28 @@ import {
type AncestorContext, type AncestorContext,
} from '@automaker/dependency-resolver'; } from '@automaker/dependency-resolver';
type FeatureData = {
title: string;
category: string;
description: string;
images: FeatureImage[];
imagePaths: DescriptionImagePath[];
textFilePaths: DescriptionTextFilePath[];
skipTests: boolean;
model: AgentModel;
thinkingLevel: ThinkingLevel;
branchName: string; // Can be empty string to use current branch
priority: number;
planningMode: PlanningMode;
requirePlanApproval: boolean;
dependencies?: string[];
};
interface AddFeatureDialogProps { interface AddFeatureDialogProps {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
onAdd: (feature: { onAdd: (feature: FeatureData) => void;
title: string; onAddAndStart?: (feature: FeatureData) => void;
category: string;
description: string;
images: FeatureImage[];
imagePaths: DescriptionImagePath[];
textFilePaths: DescriptionTextFilePath[];
skipTests: boolean;
model: AgentModel;
thinkingLevel: ThinkingLevel;
branchName: string; // Can be empty string to use current branch
priority: number;
planningMode: PlanningMode;
requirePlanApproval: boolean;
dependencies?: string[];
}) => void;
categorySuggestions: string[]; categorySuggestions: string[];
branchSuggestions: string[]; branchSuggestions: string[];
branchCardCounts?: Record<string, number>; // Map of branch name to unarchived card count branchCardCounts?: Record<string, number>; // Map of branch name to unarchived card count
@@ -92,6 +102,7 @@ export function AddFeatureDialog({
open, open,
onOpenChange, onOpenChange,
onAdd, onAdd,
onAddAndStart,
categorySuggestions, categorySuggestions,
branchSuggestions, branchSuggestions,
branchCardCounts, branchCardCounts,
@@ -188,16 +199,16 @@ export function AddFeatureDialog({
allFeatures, allFeatures,
]); ]);
const handleAdd = () => { const buildFeatureData = (): FeatureData | null => {
if (!newFeature.description.trim()) { if (!newFeature.description.trim()) {
setDescriptionError(true); setDescriptionError(true);
return; return null;
} }
// Validate branch selection when "other branch" is selected // Validate branch selection when "other branch" is selected
if (useWorktrees && !useCurrentBranch && !newFeature.branchName.trim()) { if (useWorktrees && !useCurrentBranch && !newFeature.branchName.trim()) {
toast.error('Please select a branch name'); toast.error('Please select a branch name');
return; return null;
} }
const category = newFeature.category || 'Uncategorized'; const category = newFeature.category || 'Uncategorized';
@@ -235,7 +246,7 @@ export function AddFeatureDialog({
} }
} }
onAdd({ return {
title: newFeature.title, title: newFeature.title,
category, category,
description: finalDescription, description: finalDescription,
@@ -251,9 +262,10 @@ export function AddFeatureDialog({
requirePlanApproval, requirePlanApproval,
// In spawn mode, automatically add parent as dependency // In spawn mode, automatically add parent as dependency
dependencies: isSpawnMode && parentFeature ? [parentFeature.id] : undefined, dependencies: isSpawnMode && parentFeature ? [parentFeature.id] : undefined,
}); };
};
// Reset form const resetForm = () => {
setNewFeature({ setNewFeature({
title: '', title: '',
category: '', category: '',
@@ -276,6 +288,24 @@ export function AddFeatureDialog({
onOpenChange(false); onOpenChange(false);
}; };
const handleAdd = () => {
const featureData = buildFeatureData();
if (!featureData) return;
onAdd(featureData);
resetForm();
};
const handleAddAndStart = () => {
if (!onAddAndStart) return;
const featureData = buildFeatureData();
if (!featureData) return;
onAddAndStart(featureData);
resetForm();
};
const handleDialogClose = (open: boolean) => { const handleDialogClose = (open: boolean) => {
onOpenChange(open); onOpenChange(open);
if (!open) { if (!open) {
@@ -575,6 +605,17 @@ export function AddFeatureDialog({
<Button variant="ghost" onClick={() => onOpenChange(false)}> <Button variant="ghost" onClick={() => onOpenChange(false)}>
Cancel Cancel
</Button> </Button>
{onAddAndStart && (
<Button
onClick={handleAddAndStart}
variant="secondary"
data-testid="confirm-add-and-start-feature"
disabled={useWorktrees && !useCurrentBranch && !newFeature.branchName.trim()}
>
<Play className="w-4 h-4 mr-2" />
Make
</Button>
)}
<HotkeyButton <HotkeyButton
onClick={handleAdd} onClick={handleAdd}
hotkey={{ key: 'Enter', cmdCtrl: true }} hotkey={{ key: 'Enter', cmdCtrl: true }}