mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 20:23:36 +00:00
Merge remote-tracking branch 'origin/main' into feat/extend-models-support
# Conflicts: # .automaker/feature_list.json # app/src/components/views/board-view.tsx # app/src/components/views/kanban-column.tsx # app/src/components/views/settings-view.tsx
This commit is contained in:
@@ -64,6 +64,20 @@
|
||||
--color-brand-500: var(--brand-500);
|
||||
--color-brand-600: var(--brand-600);
|
||||
|
||||
/* Action button colors */
|
||||
--color-action-view: var(--action-view);
|
||||
--color-action-view-hover: var(--action-view-hover);
|
||||
--color-action-followup: var(--action-followup);
|
||||
--color-action-followup-hover: var(--action-followup-hover);
|
||||
--color-action-commit: var(--action-commit);
|
||||
--color-action-commit-hover: var(--action-commit-hover);
|
||||
--color-action-verify: var(--action-verify);
|
||||
--color-action-verify-hover: var(--action-verify-hover);
|
||||
|
||||
/* Running task indicator colors */
|
||||
--color-running-indicator: var(--running-indicator);
|
||||
--color-running-indicator-text: var(--running-indicator-text);
|
||||
|
||||
/* Border radius */
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
@@ -113,6 +127,20 @@
|
||||
--brand-400: oklch(0.6 0.22 265);
|
||||
--brand-500: oklch(0.55 0.25 265);
|
||||
--brand-600: oklch(0.5 0.28 270);
|
||||
|
||||
/* Action button colors - Light mode */
|
||||
--action-view: oklch(0.55 0.25 265); /* Purple */
|
||||
--action-view-hover: oklch(0.5 0.28 270);
|
||||
--action-followup: oklch(0.55 0.2 230); /* Blue */
|
||||
--action-followup-hover: oklch(0.5 0.22 230);
|
||||
--action-commit: oklch(0.55 0.2 140); /* Green */
|
||||
--action-commit-hover: oklch(0.5 0.22 140);
|
||||
--action-verify: oklch(0.55 0.2 140); /* Green */
|
||||
--action-verify-hover: oklch(0.5 0.22 140);
|
||||
|
||||
/* Running indicator - Purple */
|
||||
--running-indicator: oklch(0.55 0.25 265);
|
||||
--running-indicator-text: oklch(0.6 0.22 265);
|
||||
}
|
||||
|
||||
.light {
|
||||
@@ -156,6 +184,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.9 0 0);
|
||||
--sidebar-ring: oklch(0.55 0.25 265);
|
||||
|
||||
/* Action button colors */
|
||||
--action-view: oklch(0.55 0.25 265); /* Purple */
|
||||
--action-view-hover: oklch(0.5 0.28 270);
|
||||
--action-followup: oklch(0.55 0.2 230); /* Blue */
|
||||
--action-followup-hover: oklch(0.5 0.22 230);
|
||||
--action-commit: oklch(0.55 0.2 140); /* Green */
|
||||
--action-commit-hover: oklch(0.5 0.22 140);
|
||||
--action-verify: oklch(0.55 0.2 140); /* Green */
|
||||
--action-verify-hover: oklch(0.5 0.22 140);
|
||||
|
||||
/* Running indicator - Purple */
|
||||
--running-indicator: oklch(0.55 0.25 265);
|
||||
--running-indicator-text: oklch(0.6 0.22 265);
|
||||
}
|
||||
|
||||
.dark {
|
||||
@@ -213,6 +255,20 @@
|
||||
--sidebar-accent-foreground: oklch(1 0 0);
|
||||
--sidebar-border: oklch(1 0 0 / 0.1); /* white/10 for glass borders */
|
||||
--sidebar-ring: oklch(0.55 0.25 265);
|
||||
|
||||
/* Action button colors */
|
||||
--action-view: oklch(0.6 0.25 265); /* Purple */
|
||||
--action-view-hover: oklch(0.55 0.27 270);
|
||||
--action-followup: oklch(0.6 0.2 230); /* Blue */
|
||||
--action-followup-hover: oklch(0.55 0.22 230);
|
||||
--action-commit: oklch(0.55 0.2 140); /* Green */
|
||||
--action-commit-hover: oklch(0.5 0.22 140);
|
||||
--action-verify: oklch(0.55 0.2 140); /* Green */
|
||||
--action-verify-hover: oklch(0.5 0.22 140);
|
||||
|
||||
/* Running indicator - Purple */
|
||||
--running-indicator: oklch(0.6 0.25 265);
|
||||
--running-indicator-text: oklch(0.65 0.22 265);
|
||||
}
|
||||
|
||||
.retro {
|
||||
@@ -278,6 +334,20 @@
|
||||
|
||||
/* Fonts */
|
||||
--font-sans: var(--font-geist-mono); /* Force Mono everywhere */
|
||||
|
||||
/* Action button colors - All green neon for retro theme */
|
||||
--action-view: oklch(0.85 0.25 145); /* Neon Green */
|
||||
--action-view-hover: oklch(0.9 0.25 145);
|
||||
--action-followup: oklch(0.85 0.25 145); /* Neon Green */
|
||||
--action-followup-hover: oklch(0.9 0.25 145);
|
||||
--action-commit: oklch(0.85 0.25 145); /* Neon Green */
|
||||
--action-commit-hover: oklch(0.9 0.25 145);
|
||||
--action-verify: oklch(0.85 0.25 145); /* Neon Green */
|
||||
--action-verify-hover: oklch(0.9 0.25 145);
|
||||
|
||||
/* Running indicator - Neon Green for retro */
|
||||
--running-indicator: oklch(0.85 0.25 145);
|
||||
--running-indicator-text: oklch(0.85 0.25 145);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -336,6 +406,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.95 0.01 280);
|
||||
--sidebar-border: oklch(0.35 0.05 280);
|
||||
--sidebar-ring: oklch(0.7 0.2 320);
|
||||
|
||||
/* Action button colors - Dracula purple/pink theme */
|
||||
--action-view: oklch(0.7 0.2 320); /* Purple */
|
||||
--action-view-hover: oklch(0.65 0.22 320);
|
||||
--action-followup: oklch(0.65 0.25 350); /* Pink */
|
||||
--action-followup-hover: oklch(0.6 0.27 350);
|
||||
--action-commit: oklch(0.75 0.2 130); /* Green */
|
||||
--action-commit-hover: oklch(0.7 0.22 130);
|
||||
--action-verify: oklch(0.75 0.2 130); /* Green */
|
||||
--action-verify-hover: oklch(0.7 0.22 130);
|
||||
|
||||
/* Running indicator - Purple */
|
||||
--running-indicator: oklch(0.7 0.2 320);
|
||||
--running-indicator-text: oklch(0.75 0.18 320);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -394,6 +478,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.9 0.01 230);
|
||||
--sidebar-border: oklch(0.35 0.03 240);
|
||||
--sidebar-ring: oklch(0.7 0.12 220);
|
||||
|
||||
/* Action button colors - Nord frost blue theme */
|
||||
--action-view: oklch(0.7 0.12 220); /* Frost blue */
|
||||
--action-view-hover: oklch(0.65 0.14 220);
|
||||
--action-followup: oklch(0.65 0.14 220); /* Darker frost */
|
||||
--action-followup-hover: oklch(0.6 0.16 220);
|
||||
--action-commit: oklch(0.7 0.15 140); /* Green */
|
||||
--action-commit-hover: oklch(0.65 0.17 140);
|
||||
--action-verify: oklch(0.7 0.15 140); /* Green */
|
||||
--action-verify-hover: oklch(0.65 0.17 140);
|
||||
|
||||
/* Running indicator - Frost blue */
|
||||
--running-indicator: oklch(0.7 0.12 220);
|
||||
--running-indicator-text: oklch(0.75 0.1 220);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -452,6 +550,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.95 0.02 100);
|
||||
--sidebar-border: oklch(0.35 0.03 90);
|
||||
--sidebar-ring: oklch(0.8 0.2 350);
|
||||
|
||||
/* Action button colors - Monokai pink/yellow theme */
|
||||
--action-view: oklch(0.8 0.2 350); /* Pink */
|
||||
--action-view-hover: oklch(0.75 0.22 350);
|
||||
--action-followup: oklch(0.75 0.2 200); /* Cyan */
|
||||
--action-followup-hover: oklch(0.7 0.22 200);
|
||||
--action-commit: oklch(0.8 0.2 140); /* Green */
|
||||
--action-commit-hover: oklch(0.75 0.22 140);
|
||||
--action-verify: oklch(0.8 0.2 140); /* Green */
|
||||
--action-verify-hover: oklch(0.75 0.22 140);
|
||||
|
||||
/* Running indicator - Pink */
|
||||
--running-indicator: oklch(0.8 0.2 350);
|
||||
--running-indicator-text: oklch(0.85 0.18 350);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -510,6 +622,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.85 0.02 250);
|
||||
--sidebar-border: oklch(0.32 0.04 260);
|
||||
--sidebar-ring: oklch(0.7 0.18 280);
|
||||
|
||||
/* Action button colors - Tokyo Night blue/magenta theme */
|
||||
--action-view: oklch(0.7 0.18 280); /* Blue */
|
||||
--action-view-hover: oklch(0.65 0.2 280);
|
||||
--action-followup: oklch(0.75 0.18 200); /* Cyan */
|
||||
--action-followup-hover: oklch(0.7 0.2 200);
|
||||
--action-commit: oklch(0.75 0.18 140); /* Green */
|
||||
--action-commit-hover: oklch(0.7 0.2 140);
|
||||
--action-verify: oklch(0.75 0.18 140); /* Green */
|
||||
--action-verify-hover: oklch(0.7 0.2 140);
|
||||
|
||||
/* Running indicator - Blue */
|
||||
--running-indicator: oklch(0.7 0.18 280);
|
||||
--running-indicator-text: oklch(0.75 0.16 280);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -568,6 +694,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.75 0.02 90);
|
||||
--sidebar-border: oklch(0.35 0.03 230);
|
||||
--sidebar-ring: oklch(0.65 0.15 220);
|
||||
|
||||
/* Action button colors - Solarized blue/cyan theme */
|
||||
--action-view: oklch(0.65 0.15 220); /* Blue */
|
||||
--action-view-hover: oklch(0.6 0.17 220);
|
||||
--action-followup: oklch(0.6 0.18 180); /* Cyan */
|
||||
--action-followup-hover: oklch(0.55 0.2 180);
|
||||
--action-commit: oklch(0.65 0.2 140); /* Green */
|
||||
--action-commit-hover: oklch(0.6 0.22 140);
|
||||
--action-verify: oklch(0.65 0.2 140); /* Green */
|
||||
--action-verify-hover: oklch(0.6 0.22 140);
|
||||
|
||||
/* Running indicator - Blue */
|
||||
--running-indicator: oklch(0.65 0.15 220);
|
||||
--running-indicator-text: oklch(0.7 0.13 220);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -626,6 +766,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.85 0.05 85);
|
||||
--sidebar-border: oklch(0.35 0.03 60);
|
||||
--sidebar-ring: oklch(0.7 0.18 55);
|
||||
|
||||
/* Action button colors - Gruvbox yellow/orange theme */
|
||||
--action-view: oklch(0.7 0.18 55); /* Yellow */
|
||||
--action-view-hover: oklch(0.65 0.2 55);
|
||||
--action-followup: oklch(0.7 0.15 200); /* Aqua */
|
||||
--action-followup-hover: oklch(0.65 0.17 200);
|
||||
--action-commit: oklch(0.65 0.2 140); /* Green */
|
||||
--action-commit-hover: oklch(0.6 0.22 140);
|
||||
--action-verify: oklch(0.65 0.2 140); /* Green */
|
||||
--action-verify-hover: oklch(0.6 0.22 140);
|
||||
|
||||
/* Running indicator - Yellow */
|
||||
--running-indicator: oklch(0.7 0.18 55);
|
||||
--running-indicator-text: oklch(0.75 0.16 55);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -684,6 +838,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.9 0.01 280);
|
||||
--sidebar-border: oklch(0.35 0.03 260);
|
||||
--sidebar-ring: oklch(0.75 0.15 280);
|
||||
|
||||
/* Action button colors - Catppuccin mauve/pink theme */
|
||||
--action-view: oklch(0.75 0.15 280); /* Mauve */
|
||||
--action-view-hover: oklch(0.7 0.17 280);
|
||||
--action-followup: oklch(0.75 0.15 220); /* Blue */
|
||||
--action-followup-hover: oklch(0.7 0.17 220);
|
||||
--action-commit: oklch(0.8 0.15 160); /* Green */
|
||||
--action-commit-hover: oklch(0.75 0.17 160);
|
||||
--action-verify: oklch(0.8 0.15 160); /* Green */
|
||||
--action-verify-hover: oklch(0.75 0.17 160);
|
||||
|
||||
/* Running indicator - Mauve */
|
||||
--running-indicator: oklch(0.75 0.15 280);
|
||||
--running-indicator-text: oklch(0.8 0.13 280);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -742,6 +910,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.85 0.02 240);
|
||||
--sidebar-border: oklch(0.35 0.02 250);
|
||||
--sidebar-ring: oklch(0.7 0.18 230);
|
||||
|
||||
/* Action button colors - One Dark blue/magenta theme */
|
||||
--action-view: oklch(0.7 0.18 230); /* Blue */
|
||||
--action-view-hover: oklch(0.65 0.2 230);
|
||||
--action-followup: oklch(0.75 0.15 320); /* Magenta */
|
||||
--action-followup-hover: oklch(0.7 0.17 320);
|
||||
--action-commit: oklch(0.75 0.18 150); /* Green */
|
||||
--action-commit-hover: oklch(0.7 0.2 150);
|
||||
--action-verify: oklch(0.75 0.18 150); /* Green */
|
||||
--action-verify-hover: oklch(0.7 0.2 150);
|
||||
|
||||
/* Running indicator - Blue */
|
||||
--running-indicator: oklch(0.7 0.18 230);
|
||||
--running-indicator-text: oklch(0.75 0.16 230);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
@@ -800,6 +982,20 @@
|
||||
--sidebar-accent-foreground: oklch(0.95 0.02 320);
|
||||
--sidebar-border: oklch(0.4 0.1 290);
|
||||
--sidebar-ring: oklch(0.7 0.28 350);
|
||||
|
||||
/* Action button colors - Synthwave hot pink/cyan theme */
|
||||
--action-view: oklch(0.7 0.28 350); /* Hot pink */
|
||||
--action-view-hover: oklch(0.65 0.3 350);
|
||||
--action-followup: oklch(0.8 0.25 200); /* Cyan */
|
||||
--action-followup-hover: oklch(0.75 0.27 200);
|
||||
--action-commit: oklch(0.85 0.2 60); /* Yellow */
|
||||
--action-commit-hover: oklch(0.8 0.22 60);
|
||||
--action-verify: oklch(0.85 0.2 60); /* Yellow */
|
||||
--action-verify-hover: oklch(0.8 0.22 60);
|
||||
|
||||
/* Running indicator - Hot pink */
|
||||
--running-indicator: oklch(0.7 0.28 350);
|
||||
--running-indicator-text: oklch(0.75 0.26 350);
|
||||
}
|
||||
|
||||
@layer base {
|
||||
@@ -921,14 +1117,65 @@
|
||||
.content-bg {
|
||||
background: var(--background);
|
||||
}
|
||||
|
||||
|
||||
.light .content-bg {
|
||||
background: linear-gradient(135deg, oklch(0.99 0 0), oklch(0.98 0 0), oklch(0.99 0 0));
|
||||
}
|
||||
|
||||
|
||||
.dark .content-bg {
|
||||
background: linear-gradient(135deg, oklch(0.04 0 0), oklch(0.08 0 0), oklch(0.04 0 0));
|
||||
}
|
||||
|
||||
/* Action button utilities */
|
||||
.bg-action-view {
|
||||
background-color: var(--action-view);
|
||||
}
|
||||
|
||||
.hover\:bg-action-view-hover:hover {
|
||||
background-color: var(--action-view-hover);
|
||||
}
|
||||
|
||||
.bg-action-followup {
|
||||
background-color: var(--action-followup);
|
||||
}
|
||||
|
||||
.hover\:bg-action-followup-hover:hover {
|
||||
background-color: var(--action-followup-hover);
|
||||
}
|
||||
|
||||
.bg-action-commit {
|
||||
background-color: var(--action-commit);
|
||||
}
|
||||
|
||||
.hover\:bg-action-commit-hover:hover {
|
||||
background-color: var(--action-commit-hover);
|
||||
}
|
||||
|
||||
.bg-action-verify {
|
||||
background-color: var(--action-verify);
|
||||
}
|
||||
|
||||
.hover\:bg-action-verify-hover:hover {
|
||||
background-color: var(--action-verify-hover);
|
||||
}
|
||||
|
||||
/* Running task indicator utilities */
|
||||
.border-running-indicator {
|
||||
border-color: var(--running-indicator);
|
||||
}
|
||||
|
||||
.bg-running-indicator\/20 {
|
||||
background-color: color-mix(in oklch, var(--running-indicator), transparent 80%);
|
||||
}
|
||||
|
||||
.shadow-running-indicator\/50 {
|
||||
box-shadow: 0 10px 15px -3px color-mix(in oklch, var(--running-indicator), transparent 50%),
|
||||
0 4px 6px -4px color-mix(in oklch, var(--running-indicator), transparent 50%);
|
||||
}
|
||||
|
||||
.text-running-indicator {
|
||||
color: var(--running-indicator-text);
|
||||
}
|
||||
}
|
||||
|
||||
/* Retro Overrides for Utilities */
|
||||
|
||||
@@ -178,7 +178,7 @@ export function Sidebar() {
|
||||
[projects, setCurrentProject]
|
||||
);
|
||||
|
||||
// Handle number key presses when project picker is open
|
||||
// Handle keyboard events when project picker is open
|
||||
useEffect(() => {
|
||||
if (!isProjectPickerOpen) return;
|
||||
|
||||
@@ -189,6 +189,10 @@ export function Sidebar() {
|
||||
selectProjectByNumber(num);
|
||||
} else if (event.key === "Escape") {
|
||||
setIsProjectPickerOpen(false);
|
||||
} else if (event.key.toLowerCase() === "p") {
|
||||
// Toggle off when P is pressed while dropdown is open
|
||||
event.preventDefault();
|
||||
setIsProjectPickerOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -218,8 +222,8 @@ export function Sidebar() {
|
||||
if (projects.length > 0) {
|
||||
shortcuts.push({
|
||||
key: ACTION_SHORTCUTS.projectPicker,
|
||||
action: () => setIsProjectPickerOpen(true),
|
||||
description: "Open project picker",
|
||||
action: () => setIsProjectPickerOpen((prev) => !prev),
|
||||
description: "Toggle project picker",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -174,6 +174,7 @@ export function BoardView() {
|
||||
runningAutoTasks,
|
||||
maxConcurrency,
|
||||
setMaxConcurrency,
|
||||
defaultSkipTests,
|
||||
} = useAppStore();
|
||||
const [activeFeature, setActiveFeature] = useState<Feature | null>(null);
|
||||
const [editingFeature, setEditingFeature] = useState<Feature | null>(null);
|
||||
@@ -411,6 +412,16 @@ export function BoardView() {
|
||||
[currentProject, persistedCategories]
|
||||
);
|
||||
|
||||
// Sync skipTests default when dialog opens
|
||||
useEffect(() => {
|
||||
if (showAddDialog) {
|
||||
setNewFeature((prev) => ({
|
||||
...prev,
|
||||
skipTests: defaultSkipTests,
|
||||
}));
|
||||
}
|
||||
}, [showAddDialog, defaultSkipTests]);
|
||||
|
||||
// Auto-show activity log when auto mode starts
|
||||
useEffect(() => {
|
||||
if (autoMode.isRunning && !showActivityLog) {
|
||||
@@ -690,7 +701,7 @@ export function BoardView() {
|
||||
steps: [""],
|
||||
images: [],
|
||||
imagePaths: [],
|
||||
skipTests: false,
|
||||
skipTests: defaultSkipTests,
|
||||
model: "opus",
|
||||
thinkingLevel: "none",
|
||||
});
|
||||
@@ -1378,7 +1389,6 @@ export function BoardView() {
|
||||
title={column.title}
|
||||
color={column.color}
|
||||
count={columnFeatures.length}
|
||||
isDoubleWidth={column.id === "in_progress"}
|
||||
headerAction={
|
||||
column.id === "verified" && columnFeatures.length > 0 ? (
|
||||
<Button
|
||||
@@ -1497,18 +1507,6 @@ export function BoardView() {
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4 py-4 overflow-y-auto flex-1 min-h-0">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="category">Category</Label>
|
||||
<CategoryAutocomplete
|
||||
value={newFeature.category}
|
||||
onChange={(value) =>
|
||||
setNewFeature({ ...newFeature, category: value })
|
||||
}
|
||||
suggestions={categorySuggestions}
|
||||
placeholder="e.g., Core, UI, API"
|
||||
data-testid="feature-category-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="description">Description</Label>
|
||||
<DescriptionImageDropZone
|
||||
@@ -1524,34 +1522,16 @@ export function BoardView() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>Steps</Label>
|
||||
{newFeature.steps.map((step, index) => (
|
||||
<Input
|
||||
key={index}
|
||||
placeholder={`Step ${index + 1}`}
|
||||
value={step}
|
||||
onChange={(e) => {
|
||||
const steps = [...newFeature.steps];
|
||||
steps[index] = e.target.value;
|
||||
setNewFeature({ ...newFeature, steps });
|
||||
}}
|
||||
data-testid={`feature-step-${index}-input`}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setNewFeature({
|
||||
...newFeature,
|
||||
steps: [...newFeature.steps, ""],
|
||||
})
|
||||
<Label htmlFor="category">Category (optional)</Label>
|
||||
<CategoryAutocomplete
|
||||
value={newFeature.category}
|
||||
onChange={(value) =>
|
||||
setNewFeature({ ...newFeature, category: value })
|
||||
}
|
||||
data-testid="add-step-button"
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Add Step
|
||||
</Button>
|
||||
suggestions={categorySuggestions}
|
||||
placeholder="e.g., Core, UI, API"
|
||||
data-testid="feature-category-input"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
@@ -1675,6 +1655,40 @@ export function BoardView() {
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Verification Steps - Only shown when skipTests is enabled */}
|
||||
{newFeature.skipTests && (
|
||||
<div className="space-y-2">
|
||||
<Label>Verification Steps</Label>
|
||||
{newFeature.steps.map((step, index) => (
|
||||
<Input
|
||||
key={index}
|
||||
placeholder={`Verification step ${index + 1}`}
|
||||
value={step}
|
||||
onChange={(e) => {
|
||||
const steps = [...newFeature.steps];
|
||||
steps[index] = e.target.value;
|
||||
setNewFeature({ ...newFeature, steps });
|
||||
}}
|
||||
data-testid={`feature-step-${index}-input`}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setNewFeature({
|
||||
...newFeature,
|
||||
steps: [...newFeature.steps, ""],
|
||||
})
|
||||
}
|
||||
data-testid="add-step-button"
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Add Verification Step
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button variant="ghost" onClick={() => setShowAddDialog(false)}>
|
||||
@@ -1709,21 +1723,6 @@ export function BoardView() {
|
||||
</DialogHeader>
|
||||
{editingFeature && (
|
||||
<div className="space-y-4 py-4 overflow-y-auto flex-1 min-h-0">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="edit-category">Category</Label>
|
||||
<CategoryAutocomplete
|
||||
value={editingFeature.category}
|
||||
onChange={(value) =>
|
||||
setEditingFeature({
|
||||
...editingFeature,
|
||||
category: value,
|
||||
})
|
||||
}
|
||||
suggestions={categorySuggestions}
|
||||
placeholder="e.g., Core, UI, API"
|
||||
data-testid="edit-feature-category"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="edit-description">Description</Label>
|
||||
<Textarea
|
||||
@@ -1740,32 +1739,19 @@ export function BoardView() {
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label>Steps</Label>
|
||||
{editingFeature.steps.map((step, index) => (
|
||||
<Input
|
||||
key={index}
|
||||
value={step}
|
||||
onChange={(e) => {
|
||||
const steps = [...editingFeature.steps];
|
||||
steps[index] = e.target.value;
|
||||
setEditingFeature({ ...editingFeature, steps });
|
||||
}}
|
||||
data-testid={`edit-feature-step-${index}`}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
<Label htmlFor="edit-category">Category (optional)</Label>
|
||||
<CategoryAutocomplete
|
||||
value={editingFeature.category}
|
||||
onChange={(value) =>
|
||||
setEditingFeature({
|
||||
...editingFeature,
|
||||
steps: [...editingFeature.steps, ""],
|
||||
category: value,
|
||||
})
|
||||
}
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Add Step
|
||||
</Button>
|
||||
suggestions={categorySuggestions}
|
||||
placeholder="e.g., Core, UI, API"
|
||||
data-testid="edit-feature-category"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
@@ -1897,6 +1883,39 @@ export function BoardView() {
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Verification Steps - Only shown when skipTests is enabled */}
|
||||
{editingFeature.skipTests && (
|
||||
<div className="space-y-2">
|
||||
<Label>Verification Steps</Label>
|
||||
{editingFeature.steps.map((step, index) => (
|
||||
<Input
|
||||
key={index}
|
||||
value={step}
|
||||
placeholder={`Verification step ${index + 1}`}
|
||||
onChange={(e) => {
|
||||
const steps = [...editingFeature.steps];
|
||||
steps[index] = e.target.value;
|
||||
setEditingFeature({ ...editingFeature, steps });
|
||||
}}
|
||||
data-testid={`edit-feature-step-${index}`}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
setEditingFeature({
|
||||
...editingFeature,
|
||||
steps: [...editingFeature.steps, ""],
|
||||
})
|
||||
}
|
||||
>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Add Verification Step
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<DialogFooter>
|
||||
|
||||
@@ -194,7 +194,7 @@ export function KanbanCard({
|
||||
"cursor-grab active:cursor-grabbing transition-all backdrop-blur-sm border-border relative kanban-card-content",
|
||||
isDragging && "opacity-50 scale-105 shadow-lg",
|
||||
isCurrentAutoTask &&
|
||||
"border-purple-500 border-2 shadow-purple-500/50 shadow-lg animate-pulse"
|
||||
"border-running-indicator border-2 shadow-running-indicator/50 shadow-lg animate-pulse"
|
||||
)}
|
||||
data-testid={`kanban-card-${feature.id}`}
|
||||
{...attributes}
|
||||
@@ -225,15 +225,15 @@ export function KanbanCard({
|
||||
)}
|
||||
<CardHeader className="p-3 pb-2">
|
||||
{isCurrentAutoTask && (
|
||||
<div className="absolute top-2 right-2 flex items-center gap-2 bg-purple-500/20 border border-purple-500 rounded px-2 py-0.5">
|
||||
<Loader2 className="w-4 h-4 text-purple-400 animate-spin" />
|
||||
<span className="text-xs text-purple-400 font-medium">
|
||||
<div className="absolute top-2 right-2 flex items-center gap-2 bg-running-indicator/20 border border-running-indicator rounded px-2 py-0.5">
|
||||
<Loader2 className="w-4 h-4 text-running-indicator animate-spin" />
|
||||
<span className="text-xs text-running-indicator font-medium">
|
||||
Running...
|
||||
</span>
|
||||
{feature.startedAt && (
|
||||
<CountUpTimer
|
||||
startedAt={feature.startedAt}
|
||||
className="text-purple-400"
|
||||
className="text-running-indicator"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -491,7 +491,7 @@ export function KanbanCard({
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
className="flex-1 h-7 text-xs bg-purple-600 hover:bg-purple-700"
|
||||
className="flex-1 h-7 text-xs bg-action-view hover:bg-action-view-hover"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onViewOutput();
|
||||
@@ -526,7 +526,7 @@ export function KanbanCard({
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
className="flex-1 h-7 text-xs bg-green-600 hover:bg-green-700"
|
||||
className="flex-1 h-7 text-xs bg-action-verify hover:bg-action-verify-hover"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onManualVerify();
|
||||
@@ -540,7 +540,7 @@ export function KanbanCard({
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
className="flex-1 h-7 text-xs bg-blue-600 hover:bg-blue-700"
|
||||
className="flex-1 h-7 text-xs bg-action-verify hover:bg-action-verify-hover"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onResume();
|
||||
@@ -554,7 +554,7 @@ export function KanbanCard({
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
className="flex-1 h-7 text-xs bg-green-600 hover:bg-green-700"
|
||||
className="flex-1 h-7 text-xs bg-action-verify hover:bg-action-verify-hover"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onVerify();
|
||||
@@ -640,7 +640,7 @@ export function KanbanCard({
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
className="flex-1 h-7 text-xs bg-blue-600 hover:bg-blue-700"
|
||||
className="flex-1 h-7 text-xs bg-action-followup hover:bg-action-followup-hover"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onFollowUp();
|
||||
@@ -656,7 +656,7 @@ export function KanbanCard({
|
||||
<Button
|
||||
variant="default"
|
||||
size="sm"
|
||||
className="flex-1 h-7 text-xs bg-green-600 hover:bg-green-700"
|
||||
className="flex-1 h-7 text-xs bg-action-commit hover:bg-action-commit-hover"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onCommit();
|
||||
|
||||
@@ -10,7 +10,6 @@ interface KanbanColumnProps {
|
||||
color: string;
|
||||
count: number;
|
||||
children: ReactNode;
|
||||
isDoubleWidth?: boolean;
|
||||
headerAction?: ReactNode;
|
||||
}
|
||||
|
||||
@@ -20,7 +19,6 @@ export function KanbanColumn({
|
||||
color,
|
||||
count,
|
||||
children,
|
||||
isDoubleWidth = false,
|
||||
headerAction,
|
||||
}: KanbanColumnProps) {
|
||||
const { setNodeRef, isOver } = useDroppable({ id });
|
||||
@@ -29,8 +27,7 @@ export function KanbanColumn({
|
||||
<div
|
||||
ref={setNodeRef}
|
||||
className={cn(
|
||||
"flex flex-col h-full rounded-lg bg-card backdrop-blur-sm border border-border transition-colors",
|
||||
isDoubleWidth ? "w-[37rem]" : "w-72",
|
||||
"flex flex-col h-full rounded-lg bg-card backdrop-blur-sm border border-border transition-colors w-72",
|
||||
isOver && "bg-accent"
|
||||
)}
|
||||
data-testid={`kanban-column-${id}`}
|
||||
@@ -46,14 +43,7 @@ export function KanbanColumn({
|
||||
</div>
|
||||
|
||||
{/* Column Content */}
|
||||
<div
|
||||
className={cn(
|
||||
"flex-1 overflow-y-auto p-2",
|
||||
isDoubleWidth
|
||||
? "columns-2 gap-3 [&>*]:break-inside-avoid [&>*]:mb-3 [&>*]:overflow-hidden kanban-columns-layout"
|
||||
: "space-y-2"
|
||||
)}
|
||||
>
|
||||
<div className="flex-1 overflow-y-auto p-2 space-y-2">
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -31,8 +31,10 @@ import {
|
||||
Minimize2,
|
||||
Square,
|
||||
Maximize2,
|
||||
FlaskConical,
|
||||
} from "lucide-react";
|
||||
import { getElectronAPI } from "@/lib/electron";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
|
||||
export function SettingsView() {
|
||||
const {
|
||||
@@ -43,6 +45,8 @@ export function SettingsView() {
|
||||
setTheme,
|
||||
kanbanCardDetailLevel,
|
||||
setKanbanCardDetailLevel,
|
||||
defaultSkipTests,
|
||||
setDefaultSkipTests,
|
||||
} = useAppStore();
|
||||
const [anthropicKey, setAnthropicKey] = useState(apiKeys.anthropic);
|
||||
const [googleKey, setGoogleKey] = useState(apiKeys.google);
|
||||
@@ -956,7 +960,7 @@ export function SettingsView() {
|
||||
</div>
|
||||
<div className="p-6 space-y-4">
|
||||
<div className="space-y-3">
|
||||
<Label className="text-foreground-secondary">Detail Level</Label>
|
||||
<Label className="text-foreground">Detail Level</Label>
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<button
|
||||
onClick={() => setKanbanCardDetailLevel("minimal")}
|
||||
@@ -1016,6 +1020,49 @@ export function SettingsView() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Feature Defaults Section */}
|
||||
<div className="rounded-xl border border-border bg-card backdrop-blur-md overflow-hidden">
|
||||
<div className="p-6 border-b border-border">
|
||||
<div className="flex items-center gap-2 mb-2">
|
||||
<FlaskConical className="w-5 h-5 text-brand-500" />
|
||||
<h2 className="text-lg font-semibold text-foreground">
|
||||
Feature Defaults
|
||||
</h2>
|
||||
</div>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Configure default settings for new features.
|
||||
</p>
|
||||
</div>
|
||||
<div className="p-6 space-y-4">
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-start space-x-3">
|
||||
<Checkbox
|
||||
id="default-skip-tests"
|
||||
checked={defaultSkipTests}
|
||||
onCheckedChange={(checked) =>
|
||||
setDefaultSkipTests(checked === true)
|
||||
}
|
||||
className="mt-0.5"
|
||||
data-testid="default-skip-tests-checkbox"
|
||||
/>
|
||||
<div className="space-y-1">
|
||||
<Label
|
||||
htmlFor="default-skip-tests"
|
||||
className="text-foreground cursor-pointer font-medium"
|
||||
>
|
||||
Skip automated testing by default
|
||||
</Label>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
When enabled, new features will default to manual
|
||||
verification instead of TDD (test-driven development).
|
||||
You can still override this for individual features.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Save Button */}
|
||||
<div className="flex items-center gap-4">
|
||||
<Button
|
||||
|
||||
@@ -149,6 +149,9 @@ export interface AppState {
|
||||
|
||||
// Kanban Card Display Settings
|
||||
kanbanCardDetailLevel: KanbanCardDetailLevel; // Level of detail shown on kanban cards
|
||||
|
||||
// Feature Default Settings
|
||||
defaultSkipTests: boolean; // Default value for skip tests when creating new features
|
||||
}
|
||||
|
||||
export interface AutoModeActivity {
|
||||
@@ -226,6 +229,9 @@ export interface AppActions {
|
||||
// Kanban Card Settings actions
|
||||
setKanbanCardDetailLevel: (level: KanbanCardDetailLevel) => void;
|
||||
|
||||
// Feature Default Settings actions
|
||||
setDefaultSkipTests: (skip: boolean) => void;
|
||||
|
||||
// Reset
|
||||
reset: () => void;
|
||||
}
|
||||
@@ -252,6 +258,7 @@ const initialState: AppState = {
|
||||
autoModeActivityLog: [],
|
||||
maxConcurrency: 3, // Default to 3 concurrent agents
|
||||
kanbanCardDetailLevel: "standard", // Default to standard detail level
|
||||
defaultSkipTests: false, // Default to TDD mode (tests enabled)
|
||||
};
|
||||
|
||||
export const useAppStore = create<AppState & AppActions>()(
|
||||
@@ -494,6 +501,9 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
setKanbanCardDetailLevel: (level) =>
|
||||
set({ kanbanCardDetailLevel: level }),
|
||||
|
||||
// Feature Default Settings actions
|
||||
setDefaultSkipTests: (skip) => set({ defaultSkipTests: skip }),
|
||||
|
||||
// Reset
|
||||
reset: () => set(initialState),
|
||||
}),
|
||||
@@ -510,6 +520,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
chatHistoryOpen: state.chatHistoryOpen,
|
||||
maxConcurrency: state.maxConcurrency,
|
||||
kanbanCardDetailLevel: state.kanbanCardDetailLevel,
|
||||
defaultSkipTests: state.defaultSkipTests,
|
||||
}),
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user