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
118 lines
3.7 KiB
TypeScript
118 lines
3.7 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import { createPortal } from "react-dom";
|
|
import { Plus_Jakarta_Sans } from "next/font/google";
|
|
import { TypeSelector } from "./TypeSelector";
|
|
import { FreshIdeaSetup } from "./FreshIdeaSetup";
|
|
import { ChatImportSetup } from "./ChatImportSetup";
|
|
import { CodeImportSetup } from "./CodeImportSetup";
|
|
import { MigrateSetup } from "./MigrateSetup";
|
|
import { JM } from "./modal-theme";
|
|
|
|
const modalFont = Plus_Jakarta_Sans({
|
|
subsets: ["latin"],
|
|
weight: ["400", "500", "600", "700", "800"],
|
|
variable: "--font-justine-jakarta",
|
|
display: "swap",
|
|
});
|
|
|
|
export type CreationMode = "fresh" | "chat-import" | "code-import" | "migration";
|
|
|
|
interface CreateProjectFlowProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
workspace: string;
|
|
}
|
|
|
|
type Step = "select-type" | "setup";
|
|
|
|
export function CreateProjectFlow({ open, onOpenChange, workspace }: CreateProjectFlowProps) {
|
|
const [step, setStep] = useState<Step>("setup");
|
|
const [mode, setMode] = useState<CreationMode | null>("fresh");
|
|
|
|
useEffect(() => {
|
|
if (open) {
|
|
setStep("setup");
|
|
setMode("fresh");
|
|
}
|
|
}, [open]);
|
|
|
|
useEffect(() => {
|
|
if (!open) return;
|
|
const handler = (e: KeyboardEvent) => { if (e.key === "Escape") onOpenChange(false); };
|
|
window.addEventListener("keydown", handler);
|
|
return () => window.removeEventListener("keydown", handler);
|
|
}, [open, onOpenChange]);
|
|
|
|
if (!open) return null;
|
|
|
|
const handleSelectType = (selected: CreationMode) => {
|
|
setMode(selected);
|
|
setStep("setup");
|
|
};
|
|
|
|
const handleBack = () => {
|
|
setStep("select-type");
|
|
setMode(null);
|
|
};
|
|
|
|
const setupProps = { workspace, onClose: () => onOpenChange(false), onBack: handleBack };
|
|
|
|
return createPortal(
|
|
<>
|
|
<style>{`
|
|
@keyframes vibn-fadeIn { from { opacity:0; } to { opacity:1; } }
|
|
@keyframes vibn-slideUp { from { opacity:0; transform:translateY(14px); } to { opacity:1; transform:translateY(0); } }
|
|
@keyframes vibn-spin { to { transform:rotate(360deg); } }
|
|
`}</style>
|
|
|
|
{/* Backdrop */}
|
|
<div
|
|
onClick={() => onOpenChange(false)}
|
|
style={{
|
|
position: "fixed", inset: 0, zIndex: 200,
|
|
background: JM.overlay,
|
|
backdropFilter: "blur(2px)",
|
|
WebkitBackdropFilter: "blur(2px)",
|
|
animation: "vibn-fadeIn 0.15s ease",
|
|
}}
|
|
/>
|
|
|
|
{/* Modal container — matches justine/03_dashboard.html #modal-new */}
|
|
<div style={{
|
|
position: "fixed", inset: 0, zIndex: 201,
|
|
display: "flex", alignItems: "center", justifyContent: "center",
|
|
padding: 24, pointerEvents: "none",
|
|
}}>
|
|
<div
|
|
onClick={e => e.stopPropagation()}
|
|
className={modalFont.variable}
|
|
style={{
|
|
background: "#fff", borderRadius: 16,
|
|
boxShadow: JM.cardShadow,
|
|
width: "100%",
|
|
maxWidth: JM.cardMaxWidth,
|
|
fontFamily: JM.fontSans,
|
|
pointerEvents: "all",
|
|
animation: "vibn-slideUp 0.18s cubic-bezier(0.4,0,0.2,1)",
|
|
overflow: "hidden",
|
|
}}
|
|
>
|
|
{step === "select-type" && (
|
|
<TypeSelector
|
|
onSelect={handleSelectType}
|
|
onClose={() => onOpenChange(false)}
|
|
/>
|
|
)}
|
|
{step === "setup" && mode === "fresh" && <FreshIdeaSetup {...setupProps} />}
|
|
{step === "setup" && mode === "chat-import" && <ChatImportSetup {...setupProps} />}
|
|
{step === "setup" && mode === "code-import" && <CodeImportSetup {...setupProps} />}
|
|
{step === "setup" && mode === "migration" && <MigrateSetup {...setupProps} />}
|
|
</div>
|
|
</div>
|
|
</>,
|
|
document.body
|
|
);
|
|
}
|