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]
);
// 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
// Use a ref to track the latest auto mode state so async operations always check the current value
const autoModeRunningRef = useRef(autoMode.isRunning);
@@ -1137,6 +1160,7 @@ export function BoardView() {
}
}}
onAdd={handleAddFeature}
onAddAndStart={handleAddAndStartFeature}
categorySuggestions={categorySuggestions}
branchSuggestions={branchSuggestions}
branchCardCounts={branchCardCounts}

View File

@@ -19,7 +19,14 @@ import {
FeatureTextFilePath as DescriptionTextFilePath,
ImagePreviewMap,
} 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 { getElectronAPI } from '@/lib/electron';
import { modelSupportsThinking } from '@/lib/utils';
@@ -55,25 +62,28 @@ import {
type AncestorContext,
} 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 {
open: boolean;
onOpenChange: (open: boolean) => void;
onAdd: (feature: {
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[];
}) => void;
onAdd: (feature: FeatureData) => void;
onAddAndStart?: (feature: FeatureData) => void;
categorySuggestions: string[];
branchSuggestions: string[];
branchCardCounts?: Record<string, number>; // Map of branch name to unarchived card count
@@ -92,6 +102,7 @@ export function AddFeatureDialog({
open,
onOpenChange,
onAdd,
onAddAndStart,
categorySuggestions,
branchSuggestions,
branchCardCounts,
@@ -188,16 +199,16 @@ export function AddFeatureDialog({
allFeatures,
]);
const handleAdd = () => {
const buildFeatureData = (): FeatureData | null => {
if (!newFeature.description.trim()) {
setDescriptionError(true);
return;
return null;
}
// Validate branch selection when "other branch" is selected
if (useWorktrees && !useCurrentBranch && !newFeature.branchName.trim()) {
toast.error('Please select a branch name');
return;
return null;
}
const category = newFeature.category || 'Uncategorized';
@@ -235,7 +246,7 @@ export function AddFeatureDialog({
}
}
onAdd({
return {
title: newFeature.title,
category,
description: finalDescription,
@@ -251,9 +262,10 @@ export function AddFeatureDialog({
requirePlanApproval,
// In spawn mode, automatically add parent as dependency
dependencies: isSpawnMode && parentFeature ? [parentFeature.id] : undefined,
});
};
};
// Reset form
const resetForm = () => {
setNewFeature({
title: '',
category: '',
@@ -276,6 +288,24 @@ export function AddFeatureDialog({
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) => {
onOpenChange(open);
if (!open) {
@@ -575,6 +605,17 @@ export function AddFeatureDialog({
<Button variant="ghost" onClick={() => onOpenChange(false)}>
Cancel
</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
onClick={handleAdd}
hotkey={{ key: 'Enter', cmdCtrl: true }}