mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-03 21:03:08 +00:00
🗂️ refactor: implement Phase 2 folder-pattern compliance
- Move dialogs to src/components/dialogs/ folder: - delete-session-dialog.tsx - delete-all-archived-sessions-dialog.tsx - new-project-modal.tsx - workspace-picker-modal.tsx - Update all imports to reference new dialog locations - Create barrel export (index.ts) for board-view/components/kanban-card/ - Create barrel exports (index.ts) for all 11 settings-view subfolders: - api-keys/, api-keys/hooks/, appearance/, audio/, cli-status/ - components/, config/, danger-zone/, feature-defaults/ - keyboard-shortcuts/, shared/ This is Phase 2 of folder-pattern.md compliance: organizing dialogs and establishing consistent barrel export patterns across all view subfolders. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
|
||||
import { useState, useCallback } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useState, useCallback } from 'react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
@@ -8,10 +7,10 @@ import {
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "@/components/ui/dialog";
|
||||
import { useAppStore, type ThemeMode } from "@/store/app-store";
|
||||
import { getElectronAPI, type Project } from "@/lib/electron";
|
||||
import { initializeProject } from "@/lib/project-init";
|
||||
} from '@/components/ui/dialog';
|
||||
import { useAppStore, type ThemeMode } from '@/store/app-store';
|
||||
import { getElectronAPI, type Project } from '@/lib/electron';
|
||||
import { initializeProject } from '@/lib/project-init';
|
||||
import {
|
||||
FolderOpen,
|
||||
Plus,
|
||||
@@ -21,19 +20,19 @@ import {
|
||||
MessageSquare,
|
||||
ChevronDown,
|
||||
Loader2,
|
||||
} from "lucide-react";
|
||||
} from 'lucide-react';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { toast } from "sonner";
|
||||
import { WorkspacePickerModal } from "@/components/workspace-picker-modal";
|
||||
import { NewProjectModal } from "@/components/new-project-modal";
|
||||
import { getHttpApiClient } from "@/lib/http-api-client";
|
||||
import type { StarterTemplate } from "@/lib/templates";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { toast } from 'sonner';
|
||||
import { WorkspacePickerModal } from '@/components/dialogs/workspace-picker-modal';
|
||||
import { NewProjectModal } from '@/components/dialogs/new-project-modal';
|
||||
import { getHttpApiClient } from '@/lib/http-api-client';
|
||||
import type { StarterTemplate } from '@/lib/templates';
|
||||
import { useNavigate } from '@tanstack/react-router';
|
||||
|
||||
export function WelcomeView() {
|
||||
const {
|
||||
@@ -66,24 +65,24 @@ export function WelcomeView() {
|
||||
const api = getElectronAPI();
|
||||
|
||||
if (!api.autoMode?.analyzeProject) {
|
||||
console.log("[Welcome] Auto mode API not available, skipping analysis");
|
||||
console.log('[Welcome] Auto mode API not available, skipping analysis');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsAnalyzing(true);
|
||||
try {
|
||||
console.log("[Welcome] Starting project analysis for:", projectPath);
|
||||
console.log('[Welcome] Starting project analysis for:', projectPath);
|
||||
const result = await api.autoMode.analyzeProject(projectPath);
|
||||
|
||||
if (result.success) {
|
||||
toast.success("Project analyzed", {
|
||||
description: "AI agent has analyzed your project structure",
|
||||
toast.success('Project analyzed', {
|
||||
description: 'AI agent has analyzed your project structure',
|
||||
});
|
||||
} else {
|
||||
console.error("[Welcome] Project analysis failed:", result.error);
|
||||
console.error('[Welcome] Project analysis failed:', result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Welcome] Failed to analyze project:", error);
|
||||
console.error('[Welcome] Failed to analyze project:', error);
|
||||
} finally {
|
||||
setIsAnalyzing(false);
|
||||
}
|
||||
@@ -100,8 +99,8 @@ export function WelcomeView() {
|
||||
const initResult = await initializeProject(path);
|
||||
|
||||
if (!initResult.success) {
|
||||
toast.error("Failed to initialize project", {
|
||||
description: initResult.error || "Unknown error occurred",
|
||||
toast.error('Failed to initialize project', {
|
||||
description: initResult.error || 'Unknown error occurred',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -126,26 +125,23 @@ export function WelcomeView() {
|
||||
setShowInitDialog(true);
|
||||
|
||||
// Kick off agent to analyze the project and update app_spec.txt
|
||||
console.log(
|
||||
"[Welcome] Project initialized, created files:",
|
||||
initResult.createdFiles
|
||||
);
|
||||
console.log("[Welcome] Kicking off project analysis agent...");
|
||||
console.log('[Welcome] Project initialized, created files:', initResult.createdFiles);
|
||||
console.log('[Welcome] Kicking off project analysis agent...');
|
||||
|
||||
// Start analysis in background (don't await, let it run async)
|
||||
analyzeProject(path);
|
||||
} else {
|
||||
toast.success("Project opened", {
|
||||
toast.success('Project opened', {
|
||||
description: `Opened ${name}`,
|
||||
});
|
||||
}
|
||||
|
||||
// Navigate to the board view
|
||||
navigate({ to: "/board" });
|
||||
navigate({ to: '/board' });
|
||||
} catch (error) {
|
||||
console.error("[Welcome] Failed to open project:", error);
|
||||
toast.error("Failed to open project", {
|
||||
description: error instanceof Error ? error.message : "Unknown error",
|
||||
console.error('[Welcome] Failed to open project:', error);
|
||||
toast.error('Failed to open project', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
} finally {
|
||||
setIsOpening(false);
|
||||
@@ -178,21 +174,19 @@ export function WelcomeView() {
|
||||
if (!result.canceled && result.filePaths[0]) {
|
||||
const path = result.filePaths[0];
|
||||
// Extract folder name from path (works on both Windows and Mac/Linux)
|
||||
const name =
|
||||
path.split(/[/\\]/).filter(Boolean).pop() || "Untitled Project";
|
||||
const name = path.split(/[/\\]/).filter(Boolean).pop() || 'Untitled Project';
|
||||
await initializeAndOpenProject(path, name);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Welcome] Failed to check workspace config:", error);
|
||||
console.error('[Welcome] Failed to check workspace config:', error);
|
||||
// Fall back to current behavior on error
|
||||
const api = getElectronAPI();
|
||||
const result = await api.openDirectory();
|
||||
|
||||
if (!result.canceled && result.filePaths[0]) {
|
||||
const path = result.filePaths[0];
|
||||
const name =
|
||||
path.split(/[/\\]/).filter(Boolean).pop() || "Untitled Project";
|
||||
const name = path.split(/[/\\]/).filter(Boolean).pop() || 'Untitled Project';
|
||||
await initializeAndOpenProject(path, name);
|
||||
}
|
||||
}
|
||||
@@ -224,16 +218,13 @@ export function WelcomeView() {
|
||||
};
|
||||
|
||||
const handleInteractiveMode = () => {
|
||||
navigate({ to: "/interview" });
|
||||
navigate({ to: '/interview' });
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a blank project with just .automaker directory structure
|
||||
*/
|
||||
const handleCreateBlankProject = async (
|
||||
projectName: string,
|
||||
parentDir: string
|
||||
) => {
|
||||
const handleCreateBlankProject = async (projectName: string, parentDir: string) => {
|
||||
setIsCreating(true);
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
@@ -242,7 +233,7 @@ export function WelcomeView() {
|
||||
// Validate that parent directory exists
|
||||
const parentExists = await api.exists(parentDir);
|
||||
if (!parentExists) {
|
||||
toast.error("Parent directory does not exist", {
|
||||
toast.error('Parent directory does not exist', {
|
||||
description: `Cannot create project in non-existent directory: ${parentDir}`,
|
||||
});
|
||||
return;
|
||||
@@ -251,7 +242,7 @@ export function WelcomeView() {
|
||||
// Verify parent is actually a directory
|
||||
const parentStat = await api.stat(parentDir);
|
||||
if (parentStat && !parentStat.isDirectory) {
|
||||
toast.error("Parent path is not a directory", {
|
||||
toast.error('Parent path is not a directory', {
|
||||
description: `${parentDir} is not a directory`,
|
||||
});
|
||||
return;
|
||||
@@ -260,8 +251,8 @@ export function WelcomeView() {
|
||||
// Create project directory
|
||||
const mkdirResult = await api.mkdir(projectPath);
|
||||
if (!mkdirResult.success) {
|
||||
toast.error("Failed to create project directory", {
|
||||
description: mkdirResult.error || "Unknown error occurred",
|
||||
toast.error('Failed to create project directory', {
|
||||
description: mkdirResult.error || 'Unknown error occurred',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -270,8 +261,8 @@ export function WelcomeView() {
|
||||
const initResult = await initializeProject(projectPath);
|
||||
|
||||
if (!initResult.success) {
|
||||
toast.error("Failed to initialize project", {
|
||||
description: initResult.error || "Unknown error occurred",
|
||||
toast.error('Failed to initialize project', {
|
||||
description: initResult.error || 'Unknown error occurred',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -313,7 +304,7 @@ export function WelcomeView() {
|
||||
setCurrentProject(project);
|
||||
setShowNewProjectModal(false);
|
||||
|
||||
toast.success("Project created", {
|
||||
toast.success('Project created', {
|
||||
description: `Created ${projectName} with .automaker directory`,
|
||||
});
|
||||
|
||||
@@ -326,9 +317,9 @@ export function WelcomeView() {
|
||||
});
|
||||
setShowInitDialog(true);
|
||||
} catch (error) {
|
||||
console.error("Failed to create project:", error);
|
||||
toast.error("Failed to create project", {
|
||||
description: error instanceof Error ? error.message : "Unknown error",
|
||||
console.error('Failed to create project:', error);
|
||||
toast.error('Failed to create project', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
@@ -356,8 +347,8 @@ export function WelcomeView() {
|
||||
);
|
||||
|
||||
if (!cloneResult.success || !cloneResult.projectPath) {
|
||||
toast.error("Failed to clone template", {
|
||||
description: cloneResult.error || "Unknown error occurred",
|
||||
toast.error('Failed to clone template', {
|
||||
description: cloneResult.error || 'Unknown error occurred',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -368,8 +359,8 @@ export function WelcomeView() {
|
||||
const initResult = await initializeProject(projectPath);
|
||||
|
||||
if (!initResult.success) {
|
||||
toast.error("Failed to initialize project", {
|
||||
description: initResult.error || "Unknown error occurred",
|
||||
toast.error('Failed to initialize project', {
|
||||
description: initResult.error || 'Unknown error occurred',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -387,15 +378,11 @@ export function WelcomeView() {
|
||||
</overview>
|
||||
|
||||
<technology_stack>
|
||||
${template.techStack
|
||||
.map((tech) => `<technology>${tech}</technology>`)
|
||||
.join("\n ")}
|
||||
${template.techStack.map((tech) => `<technology>${tech}</technology>`).join('\n ')}
|
||||
</technology_stack>
|
||||
|
||||
<core_capabilities>
|
||||
${template.features
|
||||
.map((feature) => `<capability>${feature}</capability>`)
|
||||
.join("\n ")}
|
||||
${template.features.map((feature) => `<capability>${feature}</capability>`).join('\n ')}
|
||||
</core_capabilities>
|
||||
|
||||
<implemented_features>
|
||||
@@ -415,7 +402,7 @@ export function WelcomeView() {
|
||||
setCurrentProject(project);
|
||||
setShowNewProjectModal(false);
|
||||
|
||||
toast.success("Project created from template", {
|
||||
toast.success('Project created from template', {
|
||||
description: `Created ${projectName} from ${template.name}`,
|
||||
});
|
||||
|
||||
@@ -431,9 +418,9 @@ export function WelcomeView() {
|
||||
// Kick off project analysis
|
||||
analyzeProject(projectPath);
|
||||
} catch (error) {
|
||||
console.error("Failed to create project from template:", error);
|
||||
toast.error("Failed to create project", {
|
||||
description: error instanceof Error ? error.message : "Unknown error",
|
||||
console.error('Failed to create project from template:', error);
|
||||
toast.error('Failed to create project', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
@@ -454,15 +441,11 @@ export function WelcomeView() {
|
||||
const api = getElectronAPI();
|
||||
|
||||
// Clone the repository
|
||||
const cloneResult = await httpClient.templates.clone(
|
||||
repoUrl,
|
||||
projectName,
|
||||
parentDir
|
||||
);
|
||||
const cloneResult = await httpClient.templates.clone(repoUrl, projectName, parentDir);
|
||||
|
||||
if (!cloneResult.success || !cloneResult.projectPath) {
|
||||
toast.error("Failed to clone repository", {
|
||||
description: cloneResult.error || "Unknown error occurred",
|
||||
toast.error('Failed to clone repository', {
|
||||
description: cloneResult.error || 'Unknown error occurred',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -473,8 +456,8 @@ export function WelcomeView() {
|
||||
const initResult = await initializeProject(projectPath);
|
||||
|
||||
if (!initResult.success) {
|
||||
toast.error("Failed to initialize project", {
|
||||
description: initResult.error || "Unknown error occurred",
|
||||
toast.error('Failed to initialize project', {
|
||||
description: initResult.error || 'Unknown error occurred',
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -516,7 +499,7 @@ export function WelcomeView() {
|
||||
setCurrentProject(project);
|
||||
setShowNewProjectModal(false);
|
||||
|
||||
toast.success("Project created from repository", {
|
||||
toast.success('Project created from repository', {
|
||||
description: `Created ${projectName} from ${repoUrl}`,
|
||||
});
|
||||
|
||||
@@ -532,9 +515,9 @@ export function WelcomeView() {
|
||||
// Kick off project analysis
|
||||
analyzeProject(projectPath);
|
||||
} catch (error) {
|
||||
console.error("Failed to create project from custom URL:", error);
|
||||
toast.error("Failed to create project", {
|
||||
description: error instanceof Error ? error.message : "Unknown error",
|
||||
console.error('Failed to create project from custom URL:', error);
|
||||
toast.error('Failed to create project', {
|
||||
description: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
@@ -587,12 +570,9 @@ export function WelcomeView() {
|
||||
<Plus className="w-6 h-6 text-white" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="text-lg font-semibold text-foreground mb-1.5">
|
||||
New Project
|
||||
</h3>
|
||||
<h3 className="text-lg font-semibold text-foreground mb-1.5">New Project</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Create a new project from scratch with AI-powered
|
||||
development
|
||||
Create a new project from scratch with AI-powered development
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -608,10 +588,7 @@ export function WelcomeView() {
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-56">
|
||||
<DropdownMenuItem
|
||||
onClick={handleNewProject}
|
||||
data-testid="quick-setup-option"
|
||||
>
|
||||
<DropdownMenuItem onClick={handleNewProject} data-testid="quick-setup-option">
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
Quick Setup
|
||||
</DropdownMenuItem>
|
||||
@@ -640,9 +617,7 @@ export function WelcomeView() {
|
||||
<FolderOpen className="w-6 h-6 text-muted-foreground group-hover:text-blue-500 transition-colors duration-300" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<h3 className="text-lg font-semibold text-foreground mb-1.5">
|
||||
Open Project
|
||||
</h3>
|
||||
<h3 className="text-lg font-semibold text-foreground mb-1.5">Open Project</h3>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
Open an existing project folder to continue working
|
||||
</p>
|
||||
@@ -667,9 +642,7 @@ export function WelcomeView() {
|
||||
<div className="w-8 h-8 rounded-lg bg-muted/50 flex items-center justify-center">
|
||||
<Clock className="w-4 h-4 text-muted-foreground" />
|
||||
</div>
|
||||
<h2 className="text-lg font-semibold text-foreground">
|
||||
Recent Projects
|
||||
</h2>
|
||||
<h2 className="text-lg font-semibold text-foreground">Recent Projects</h2>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{recentProjects.map((project, index) => (
|
||||
@@ -695,9 +668,7 @@ export function WelcomeView() {
|
||||
</p>
|
||||
{project.lastOpened && (
|
||||
<p className="text-xs text-muted-foreground mt-1.5">
|
||||
{new Date(
|
||||
project.lastOpened
|
||||
).toLocaleDateString()}
|
||||
{new Date(project.lastOpened).toLocaleDateString()}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -715,9 +686,7 @@ export function WelcomeView() {
|
||||
<div className="w-20 h-20 rounded-2xl bg-muted/50 border border-border flex items-center justify-center mb-5">
|
||||
<Sparkles className="w-10 h-10 text-muted-foreground/50" />
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold text-foreground mb-2">
|
||||
No projects yet
|
||||
</h3>
|
||||
<h3 className="text-xl font-semibold text-foreground mb-2">No projects yet</h3>
|
||||
<p className="text-sm text-muted-foreground max-w-md leading-relaxed">
|
||||
Get started by creating a new project or opening an existing one
|
||||
</p>
|
||||
@@ -747,9 +716,7 @@ export function WelcomeView() {
|
||||
<div className="w-8 h-8 rounded-lg bg-brand-500/10 flex items-center justify-center">
|
||||
<Sparkles className="w-4 h-4 text-brand-500" />
|
||||
</div>
|
||||
{initStatus?.isNewProject
|
||||
? "Project Initialized"
|
||||
: "Project Updated"}
|
||||
{initStatus?.isNewProject ? 'Project Initialized' : 'Project Updated'}
|
||||
</DialogTitle>
|
||||
<DialogDescription className="text-muted-foreground mt-1">
|
||||
{initStatus?.isNewProject
|
||||
@@ -759,9 +726,7 @@ export function WelcomeView() {
|
||||
</DialogHeader>
|
||||
<div className="py-4">
|
||||
<div className="space-y-3">
|
||||
<p className="text-sm text-foreground font-medium">
|
||||
Created files:
|
||||
</p>
|
||||
<p className="text-sm text-foreground font-medium">Created files:</p>
|
||||
<ul className="space-y-2">
|
||||
{initStatus?.createdFiles.map((file) => (
|
||||
<li
|
||||
@@ -788,12 +753,12 @@ export function WelcomeView() {
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
<span className="text-brand-500 font-medium">Tip:</span> Edit the{" "}
|
||||
<span className="text-brand-500 font-medium">Tip:</span> Edit the{' '}
|
||||
<code className="text-xs bg-muted px-1.5 py-0.5 rounded font-mono">
|
||||
app_spec.txt
|
||||
</code>{" "}
|
||||
file to describe your project. The AI agent will use this to
|
||||
understand your project structure.
|
||||
</code>{' '}
|
||||
file to describe your project. The AI agent will use this to understand your
|
||||
project structure.
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -826,9 +791,7 @@ export function WelcomeView() {
|
||||
>
|
||||
<div className="flex flex-col items-center gap-4 p-8 rounded-2xl bg-card border border-border shadow-2xl">
|
||||
<Loader2 className="w-10 h-10 text-brand-500 animate-spin" />
|
||||
<p className="text-foreground font-medium">
|
||||
Initializing project...
|
||||
</p>
|
||||
<p className="text-foreground font-medium">Initializing project...</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user