mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-03-17 02:43:09 +00:00
feat: add project reset functionality with quick and full reset options
Add the ability to reset a project to its initial state with two options:
- Quick Reset: Clears features.db, assistant.db, and settings files while
preserving app spec and prompts
- Full Reset: Deletes everything including prompts directory, triggering
the setup wizard for project reconfiguration
Backend changes:
- Add POST /{name}/reset endpoint to projects router with full_reset query param
- Validate agent lock file to prevent reset while agent is running (409 Conflict)
- Dispose database engines before deleting files to release Windows file locks
- Add engine caching to api/database.py for better connection management
- Add dispose_engine() functions to both database modules
- Delete WAL mode journal files (*.db-wal, *.db-shm) during reset
Frontend changes:
- Add ResetProjectModal component with toggle between Quick/Full reset modes
- Add ProjectSetupRequired component shown when has_spec is false
- Add resetProject API function and useResetProject React Query hook
- Integrate reset button in header (disabled when agent running)
- Add 'R' keyboard shortcut to open reset modal
- Show ProjectSetupRequired when project needs setup after full reset
This implements the feature from PR #4 directly on master to avoid merge
conflicts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,8 +26,10 @@ import { ViewToggle, type ViewMode } from './components/ViewToggle'
|
||||
import { DependencyGraph } from './components/DependencyGraph'
|
||||
import { KeyboardShortcutsHelp } from './components/KeyboardShortcutsHelp'
|
||||
import { ThemeSelector } from './components/ThemeSelector'
|
||||
import { ResetProjectModal } from './components/ResetProjectModal'
|
||||
import { ProjectSetupRequired } from './components/ProjectSetupRequired'
|
||||
import { getDependencyGraph } from './lib/api'
|
||||
import { Loader2, Settings, Moon, Sun } from 'lucide-react'
|
||||
import { Loader2, Settings, Moon, Sun, RotateCcw } from 'lucide-react'
|
||||
import type { Feature } from './lib/types'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card, CardContent } from '@/components/ui/card'
|
||||
@@ -59,6 +61,7 @@ function App() {
|
||||
const [showSettings, setShowSettings] = useState(false)
|
||||
const [showKeyboardHelp, setShowKeyboardHelp] = useState(false)
|
||||
const [isSpecCreating, setIsSpecCreating] = useState(false)
|
||||
const [showResetModal, setShowResetModal] = useState(false)
|
||||
const [showSpecChat, setShowSpecChat] = useState(false) // For "Create Spec" button in empty kanban
|
||||
const [viewMode, setViewMode] = useState<ViewMode>(() => {
|
||||
try {
|
||||
@@ -203,10 +206,18 @@ function App() {
|
||||
setShowKeyboardHelp(true)
|
||||
}
|
||||
|
||||
// R : Open reset modal (when project selected and agent not running)
|
||||
if ((e.key === 'r' || e.key === 'R') && selectedProject && wsState.agentStatus !== 'running') {
|
||||
e.preventDefault()
|
||||
setShowResetModal(true)
|
||||
}
|
||||
|
||||
// Escape : Close modals
|
||||
if (e.key === 'Escape') {
|
||||
if (showKeyboardHelp) {
|
||||
setShowKeyboardHelp(false)
|
||||
} else if (showResetModal) {
|
||||
setShowResetModal(false)
|
||||
} else if (showExpandProject) {
|
||||
setShowExpandProject(false)
|
||||
} else if (showSettings) {
|
||||
@@ -225,7 +236,7 @@ function App() {
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [selectedProject, showAddFeature, showExpandProject, selectedFeature, debugOpen, debugActiveTab, assistantOpen, features, showSettings, showKeyboardHelp, isSpecCreating, viewMode])
|
||||
}, [selectedProject, showAddFeature, showExpandProject, selectedFeature, debugOpen, debugActiveTab, assistantOpen, features, showSettings, showKeyboardHelp, isSpecCreating, viewMode, showResetModal, wsState.agentStatus])
|
||||
|
||||
// Combine WebSocket progress with feature data
|
||||
const progress = wsState.progress.total > 0 ? wsState.progress : {
|
||||
@@ -287,6 +298,17 @@ function App() {
|
||||
<Settings size={18} />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={() => setShowResetModal(true)}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
title="Reset Project (R)"
|
||||
aria-label="Reset Project"
|
||||
disabled={wsState.agentStatus === 'running'}
|
||||
>
|
||||
<RotateCcw size={18} />
|
||||
</Button>
|
||||
|
||||
{/* Ollama Mode Indicator */}
|
||||
{settings?.ollama_mode && (
|
||||
<div
|
||||
@@ -346,6 +368,16 @@ function App() {
|
||||
Select a project from the dropdown above or create a new one to get started.
|
||||
</p>
|
||||
</div>
|
||||
) : !hasSpec ? (
|
||||
<ProjectSetupRequired
|
||||
projectName={selectedProject}
|
||||
projectPath={selectedProjectData?.path}
|
||||
onCreateWithClaude={() => setShowSpecChat(true)}
|
||||
onEditManually={() => {
|
||||
// Open debug panel for the user to see the project path
|
||||
setDebugOpen(true)
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className="space-y-8">
|
||||
{/* Progress Dashboard */}
|
||||
@@ -512,6 +544,21 @@ function App() {
|
||||
{/* Keyboard Shortcuts Help */}
|
||||
<KeyboardShortcutsHelp isOpen={showKeyboardHelp} onClose={() => setShowKeyboardHelp(false)} />
|
||||
|
||||
{/* Reset Project Modal */}
|
||||
{showResetModal && selectedProject && (
|
||||
<ResetProjectModal
|
||||
isOpen={showResetModal}
|
||||
projectName={selectedProject}
|
||||
onClose={() => setShowResetModal(false)}
|
||||
onResetComplete={(wasFullReset) => {
|
||||
// If full reset, the spec was deleted - show spec creation chat
|
||||
if (wasFullReset) {
|
||||
setShowSpecChat(true)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Celebration Overlay - shows when a feature is completed by an agent */}
|
||||
{wsState.celebration && (
|
||||
<CelebrationOverlay
|
||||
|
||||
Reference in New Issue
Block a user