94 lines
2.3 KiB
TypeScript
94 lines
2.3 KiB
TypeScript
|
|
import * as React from "react";
|
||
|
|
import { api } from "./api/client";
|
||
|
|
import { Chat } from "./components/Chat";
|
||
|
|
import "./App.css";
|
||
|
|
|
||
|
|
function App() {
|
||
|
|
const [projectPath, setProjectPath] = React.useState<string | null>(null);
|
||
|
|
const [errorMsg, setErrorMsg] = React.useState<string | null>(null);
|
||
|
|
const [pathInput, setPathInput] = React.useState("");
|
||
|
|
const [isOpening, setIsOpening] = React.useState(false);
|
||
|
|
|
||
|
|
async function openProject(path: string) {
|
||
|
|
if (!path.trim()) {
|
||
|
|
setErrorMsg("Please enter a project path.");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
try {
|
||
|
|
setErrorMsg(null);
|
||
|
|
setIsOpening(true);
|
||
|
|
const confirmedPath = await api.openProject(path.trim());
|
||
|
|
setProjectPath(confirmedPath);
|
||
|
|
} catch (e) {
|
||
|
|
console.error(e);
|
||
|
|
const message =
|
||
|
|
e instanceof Error
|
||
|
|
? e.message
|
||
|
|
: typeof e === "string"
|
||
|
|
? e
|
||
|
|
: "An error occurred opening the project.";
|
||
|
|
setErrorMsg(message);
|
||
|
|
} finally {
|
||
|
|
setIsOpening(false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleOpen() {
|
||
|
|
void openProject(pathInput);
|
||
|
|
}
|
||
|
|
|
||
|
|
async function closeProject() {
|
||
|
|
try {
|
||
|
|
await api.closeProject();
|
||
|
|
setProjectPath(null);
|
||
|
|
} catch (e) {
|
||
|
|
console.error(e);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<main
|
||
|
|
className="container"
|
||
|
|
style={{ height: "100vh", padding: 0, maxWidth: "100%" }}
|
||
|
|
>
|
||
|
|
{!projectPath ? (
|
||
|
|
<div
|
||
|
|
className="selection-screen"
|
||
|
|
style={{ padding: "2rem", maxWidth: "800px", margin: "0 auto" }}
|
||
|
|
>
|
||
|
|
<h1>AI Code Assistant</h1>
|
||
|
|
<p>Paste a project path to start the Story-Driven Spec Workflow.</p>
|
||
|
|
<input
|
||
|
|
type="text"
|
||
|
|
value={pathInput}
|
||
|
|
placeholder="/path/to/project"
|
||
|
|
onChange={(event) => setPathInput(event.target.value)}
|
||
|
|
onKeyDown={(event) => {
|
||
|
|
if (event.key === "Enter") {
|
||
|
|
handleOpen();
|
||
|
|
}
|
||
|
|
}}
|
||
|
|
style={{ width: "100%", padding: "10px", marginTop: "12px" }}
|
||
|
|
/>
|
||
|
|
<button type="button" onClick={handleOpen} disabled={isOpening}>
|
||
|
|
{isOpening ? "Opening..." : "Open Project"}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
) : (
|
||
|
|
<div className="workspace" style={{ height: "100%" }}>
|
||
|
|
<Chat projectPath={projectPath} onCloseProject={closeProject} />
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
|
||
|
|
{errorMsg && (
|
||
|
|
<div className="error-message" style={{ marginTop: "20px" }}>
|
||
|
|
<p style={{ color: "red" }}>Error: {errorMsg}</p>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</main>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
export default App;
|