fix: bug fix related to effect-ts refactor

This commit is contained in:
d-kimsuon
2025-10-17 17:16:08 +09:00
parent 1795cb499b
commit a5d81568bb
28 changed files with 1022 additions and 196 deletions

View File

@@ -0,0 +1,105 @@
"use client";
import { useMutation } from "@tanstack/react-query";
import { Loader2, Plus } from "lucide-react";
import { useRouter } from "next/navigation";
import { type FC, useState } from "react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { honoClient } from "@/lib/api/client";
import { DirectoryPicker } from "./DirectoryPicker";
export const CreateProjectDialog: FC = () => {
const [open, setOpen] = useState(false);
const [selectedPath, setSelectedPath] = useState<string>("");
const router = useRouter();
const createProjectMutation = useMutation({
mutationFn: async () => {
const response = await honoClient.api.projects.$post({
json: { projectPath: selectedPath },
});
if (!response.ok) {
throw new Error("Failed to create project");
}
return await response.json();
},
onSuccess: (result) => {
toast.success("Project created successfully");
setOpen(false);
router.push(`/projects/${result.projectId}/sessions/${result.sessionId}`);
},
onError: (error) => {
toast.error(
error instanceof Error ? error.message : "Failed to create project",
);
},
});
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>
<Button>
<Plus className="w-4 h-4 mr-2" />
New Project
</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>Create New Project</DialogTitle>
<DialogDescription>
Select a directory to initialize as a Claude Code project. This will
run{" "}
<code className="text-sm bg-muted px-1 py-0.5 rounded">/init</code>{" "}
in the selected directory.
</DialogDescription>
</DialogHeader>
<div className="py-4">
<DirectoryPicker
selectedPath={selectedPath}
onPathChange={setSelectedPath}
/>
{selectedPath ? (
<div className="mt-4 p-3 bg-muted rounded-md">
<p className="text-sm font-medium mb-1">Selected directory:</p>
<p className="text-sm text-muted-foreground font-mono">
{selectedPath}
</p>
</div>
) : null}
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setOpen(false)}>
Cancel
</Button>
<Button
onClick={async () => await createProjectMutation.mutateAsync()}
disabled={!selectedPath || createProjectMutation.isPending}
>
{createProjectMutation.isPending ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
Creating...
</>
) : (
"Create Project"
)}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
);
};

View File

@@ -0,0 +1,76 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { ChevronRight, Folder } from "lucide-react";
import { type FC, useState } from "react";
import { Button } from "@/components/ui/button";
import { directoryListingQuery } from "@/lib/api/queries";
export type DirectoryPickerProps = {
selectedPath: string;
onPathChange: (path: string) => void;
};
export const DirectoryPicker: FC<DirectoryPickerProps> = ({ onPathChange }) => {
const [currentPath, setCurrentPath] = useState<string | undefined>(undefined);
const { data, isLoading } = useQuery(directoryListingQuery(currentPath));
const handleNavigate = (entryPath: string) => {
if (entryPath === "") {
setCurrentPath(undefined);
return;
}
const newPath = `/${entryPath}`;
setCurrentPath(newPath);
};
const handleSelect = () => {
onPathChange(data?.currentPath || "");
};
return (
<div className="border rounded-md">
<div className="p-3 border-b bg-muted/50 flex items-center justify-between">
<p className="text-sm font-medium">
Current: <span className="font-mono">{data?.currentPath || "~"}</span>
</p>
<Button size="sm" onClick={handleSelect}>
Select This Directory
</Button>
</div>
<div className="max-h-96 overflow-auto">
{isLoading ? (
<div className="p-8 text-center text-sm text-muted-foreground">
Loading...
</div>
) : data?.entries && data.entries.length > 0 ? (
<div className="divide-y">
{data.entries
.filter((entry) => entry.type === "directory")
.map((entry) => (
<button
key={entry.path}
type="button"
onClick={() => handleNavigate(entry.path)}
className="w-full px-3 py-2 flex items-center gap-2 hover:bg-muted/50 transition-colors text-left"
>
{entry.name === ".." ? (
<ChevronRight className="w-4 h-4 rotate-180" />
) : (
<Folder className="w-4 h-4 text-blue-500" />
)}
<span className="text-sm">{entry.name}</span>
</button>
))}
</div>
) : (
<div className="p-8 text-center text-sm text-muted-foreground">
No directories found
</div>
)}
</div>
</div>
);
};

View File

@@ -59,7 +59,7 @@ export const ProjectList: FC = () => {
</CardContent>
<CardContent className="pt-0">
<Button asChild className="w-full">
<Link href={`/projects/${encodeURIComponent(project.id)}/latest`}>
<Link href={`/projects/${project.id}/latest`}>
View Conversations
</Link>
</Button>