Theia rip-out: - Delete app/api/theia-auth/route.ts (Traefik ForwardAuth shim) - Delete app/api/projects/[projectId]/workspace/route.ts and app/api/projects/prewarm/route.ts (Cloud Run Theia provisioning) - Delete lib/cloud-run-workspace.ts and lib/coolify-workspace.ts - Strip provisionTheiaWorkspace + theiaWorkspaceUrl/theiaAppUuid/ theiaError from app/api/projects/create/route.ts response - Remove Theia callbackUrl branch in app/auth/page.tsx - Drop "Open in Theia" button + xterm/Theia PTY copy in build/page.tsx - Drop theiaWorkspaceUrl from deployment/page.tsx Project type - Strip Theia IDE line + theia-code-os from advisor + agent-chat context strings - Scrub Theia mention from lib/auth/workspace-auth.ts comment P5.1 (custom apex domains + DNS): - lib/coolify.ts + lib/opensrs.ts: nameserver normalization, OpenSRS XML auth, Cloud DNS plumbing - scripts/smoke-attach-e2e.ts: full prod GCP + sandbox OpenSRS + prod Coolify smoke covering register/zone/A/NS/PATCH/cleanup In-progress (Justine onboarding/build, MVP setup, agent telemetry): - New (justine)/stories, project (home) layouts, mvp-setup, run, tasks routes + supporting components - Project shell + sidebar + nav refactor for the Stackless palette - Agent session API hardening (sessions, events, stream, approve, retry, stop) + atlas-chat, advisor, design-surfaces refresh - New scripts/sync-db-url-from-coolify.mjs + scripts/prisma-db-push.mjs + docker-compose.local-db.yml for local Prisma workflows - lib/dev-bypass.ts, lib/chat-context-refs.ts, lib/prd-sections.ts - Misc: stories CSS, debug/prisma route, modal-theme, BuildLivePlanPanel Made-with: Cursor
93 lines
2.9 KiB
TypeScript
93 lines
2.9 KiB
TypeScript
"use client";
|
||
|
||
import { useRef, useState } from "react";
|
||
import { useRouter } from "next/navigation";
|
||
import { toast } from "sonner";
|
||
import { JM } from "./modal-theme";
|
||
import { FieldLabel, TextInput, PrimaryButton, ForWhomSelector, type SetupProps } from "./setup-shared";
|
||
|
||
export function FreshIdeaSetup({ workspace, onClose }: SetupProps) {
|
||
const router = useRouter();
|
||
const [name, setName] = useState("");
|
||
const [forWhom, setForWhom] = useState<"personal" | "client">("personal");
|
||
const [loading, setLoading] = useState(false);
|
||
const nameRef = useRef<HTMLInputElement>(null);
|
||
|
||
const canCreate = name.trim().length > 0;
|
||
|
||
const handleCreate = async () => {
|
||
if (!canCreate) return;
|
||
setLoading(true);
|
||
try {
|
||
const res = await fetch("/api/projects/create", {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
body: JSON.stringify({
|
||
projectName: name.trim(),
|
||
projectType: "web-app",
|
||
slug: name.toLowerCase().replace(/[^a-z0-9]+/g, "-"),
|
||
product: { name: name.trim(), isForClient: forWhom === "client" },
|
||
creationMode: "fresh",
|
||
sourceData: {},
|
||
}),
|
||
});
|
||
if (!res.ok) {
|
||
const err = await res.json();
|
||
toast.error(err.error || "Failed to create project");
|
||
return;
|
||
}
|
||
const data = await res.json();
|
||
onClose();
|
||
router.push(`/${workspace}/project/${data.projectId}/overview`);
|
||
} catch {
|
||
toast.error("Something went wrong");
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div style={{ padding: 28 }}>
|
||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 22 }}>
|
||
<h3 style={{
|
||
fontFamily: JM.fontDisplay, fontSize: 18, fontWeight: 700,
|
||
color: JM.ink, margin: 0, letterSpacing: "-0.02em",
|
||
}}>
|
||
New project
|
||
</h3>
|
||
<button
|
||
type="button"
|
||
onClick={onClose}
|
||
style={{
|
||
background: "none", border: "none", cursor: "pointer",
|
||
color: JM.muted, fontSize: 20, padding: 4, lineHeight: 1,
|
||
fontFamily: JM.fontSans,
|
||
}}
|
||
onMouseEnter={e => (e.currentTarget.style.color = JM.mid)}
|
||
onMouseLeave={e => (e.currentTarget.style.color = JM.muted)}
|
||
>
|
||
×
|
||
</button>
|
||
</div>
|
||
|
||
<div style={{ marginBottom: 16 }}>
|
||
<FieldLabel>Project name</FieldLabel>
|
||
<TextInput
|
||
value={name}
|
||
onChange={setName}
|
||
placeholder="e.g. My SaaS App"
|
||
onKeyDown={e => { if (e.key === "Enter" && canCreate) void handleCreate(); }}
|
||
inputRef={nameRef}
|
||
autoFocus
|
||
/>
|
||
</div>
|
||
|
||
<ForWhomSelector value={forWhom} onChange={setForWhom} />
|
||
|
||
<PrimaryButton onClick={() => { void handleCreate(); }} disabled={!canCreate} loading={loading}>
|
||
Create project →
|
||
</PrimaryButton>
|
||
</div>
|
||
);
|
||
}
|