import { useMemo, useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { AlertCircle, CheckCircle2, ClipboardCheck, Download, FlaskConical, GitPullRequest, Upload, X } from "lucide-react";
import {
asWorkspaceApiError,
exportWorkspace,
getWorkspace,
getWorkspaceRegistryStatus,
importWorkspace,
listWorkspaces,
pullWorkspaceRegistry,
testWorkspace,
validateWorkspace,
type CanonicalWorkspace,
type PublishWorkspaceRequest,
type WorkspaceRecord,
type WorkspaceSummary,
} from "../api/workspaces";
import { workspaceBootstrapDrafts, type WorkspaceBootstrapDraft } from "../workspaces/drafts";
import { Button } from "../components/ui/button";
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "../components/ui/dialog";
import { WorkspaceEditor } from "./WorkspaceEditor";
import { WorkspacePublishDialog } from "./WorkspacePublishDialog";
const EMPTY_COMMIT = "0".repeat(40);
function QueryError({ name, message, retryLabel, onRetry }: {
name: string;
message: string;
retryLabel: string;
onRetry: () => void;
}) {
return
;
}
function defaultBootstrapWorkspace(summary: WorkspaceSummary): CanonicalWorkspace {
return {
workspace: {
schema_version: 3,
id: summary.id,
name: summary.displayName,
...(summary.description ? { description: summary.description } : {}),
language: "en",
},
dwh: {
engine: "postgres",
database: "database",
schema: "public",
supported_transports: ["postgres_direct"],
},
semantic_index: {
vector_store: {
engine: "qdrant",
collection: summary.id.replaceAll("-", "_"),
dimensions: 1024,
distance: "cosine",
},
embedding: {
provider: "ollama_internal",
model: "qwen3-embedding:0.6b",
dimensions: 1024,
},
},
llm_policy: { allowed: ["zai/glm-5.2"], default: "zai/glm-5.2" },
};
}
function bootstrapDraftFor(summary: WorkspaceSummary, baseCommit: string): WorkspaceBootstrapDraft {
return {
workspaceId: summary.id,
baseCommit,
workspace: defaultBootstrapWorkspace(summary),
updatedAt: new Date().toISOString(),
};
}
export function WorkspaceManager({ open, onClose }: { open: boolean; onClose: () => void }) {
const [selectedId, setSelectedId] = useState();
const [localDraft, setLocalDraft] = useState();
const [notice, setNotice] = useState();
const [diagnostics, setDiagnostics] = useState([]);
const [publishRequest, setPublishRequest] = useState();
const [transferring, setTransferring] = useState(false);
const statusQuery = useQuery({ queryKey: ["workspace-registry-status"], queryFn: getWorkspaceRegistryStatus, enabled: open });
const workspacesQuery = useQuery({ queryKey: ["workspaces"], queryFn: listWorkspaces, enabled: open });
const workspaces = workspacesQuery.data ?? [];
const selectedSummary = useMemo(() => workspaces.find((workspace) => workspace.id === selectedId), [selectedId, workspaces]);
const detailQuery = useQuery({
queryKey: ["workspace", selectedId],
queryFn: () => getWorkspace(selectedId!),
enabled: Boolean(open && selectedId && selectedSummary?.configurationState === "ready"),
});
const record = detailQuery.data;
const activeBootstrapDraft = selectedSummary?.configurationState === "configuration_required"
? (localDraft?.workspaceId === selectedSummary.id ? localDraft : workspaceBootstrapDrafts.load(selectedSummary.id) ?? bootstrapDraftFor(selectedSummary, statusQuery.data?.head ?? EMPTY_COMMIT))
: undefined;
function resetTransientState() {
setNotice(undefined);
setDiagnostics([]);
setPublishRequest(undefined);
}
function selectWorkspace(id: string) {
setSelectedId(id);
setLocalDraft(undefined);
resetTransientState();
}
function saveDraft(draft: WorkspaceBootstrapDraft) {
workspaceBootstrapDrafts.save(draft);
setLocalDraft(draft);
setSelectedId(draft.workspaceId);
setNotice("Draft saved in this browser.");
setDiagnostics([]);
}
function requestCreate(request: PublishWorkspaceRequest, draft: WorkspaceBootstrapDraft) {
workspaceBootstrapDrafts.save(draft);
setLocalDraft(draft);
setSelectedId(draft.workspaceId);
setNotice(undefined);
setDiagnostics([]);
setPublishRequest(request);
}
async function pullLatest() {
setNotice(undefined);
setDiagnostics([]);
try {
await pullWorkspaceRegistry();
await Promise.all([statusQuery.refetch(), workspacesQuery.refetch()]);
setNotice("Registry updated. Reload a workspace to review its latest revision.");
} catch (error) {
const safe = asWorkspaceApiError(error);
setDiagnostics([safe ? `${safe.code}: ${safe.message}` : "git_unavailable: Registry pull could not be completed"]);
}
}
async function validateSelectedWorkspace() {
if (!record) return;
setNotice(undefined);
setDiagnostics([]);
try {
await validateWorkspace(record.workspace);
setNotice("Workspace definition is valid.");
} catch (error) {
const safe = asWorkspaceApiError(error);
setDiagnostics([safe ? `${safe.code}: ${safe.message}` : "workspace_invalid: Validation could not be completed"]);
}
}
async function testSelectedWorkspace() {
if (!record) return;
setNotice(undefined);
setDiagnostics([]);
try {
const result = await testWorkspace(record.workspace.workspace.id);
setDiagnostics(result.diagnostics.map((diagnostic) => `${diagnostic.code}: ${diagnostic.message}`));
if (result.diagnostics.length === 0) {
setNotice(result.activatable ? "Installation test passed." : "Installation test completed.");
}
} catch (error) {
const safe = asWorkspaceApiError(error);
setDiagnostics([safe ? `${safe.code}: ${safe.message}` : "connector_unavailable: Installation test could not be completed"]);
}
}
async function downloadBundle() {
if (!record) return;
setTransferring(true);
setNotice(undefined);
setDiagnostics([]);
try {
const bundle = await exportWorkspace(record.workspace.workspace.id);
const url = URL.createObjectURL(bundle);
const link = document.createElement("a");
link.href = url;
link.download = `${record.workspace.workspace.id}.zip`;
link.click();
URL.revokeObjectURL(url);
setNotice("Workspace bundle downloaded.");
} catch (error) {
const safe = asWorkspaceApiError(error);
setDiagnostics([safe ? `${safe.code}: ${safe.message}` : "workspace_invalid: Workspace bundle could not be exported"]);
} finally {
setTransferring(false);
}
}
async function importBundle(file: File | undefined) {
if (!file) return;
setTransferring(true);
setNotice(undefined);
setDiagnostics([]);
try {
const result = await importWorkspace(file);
const importedId = result.draft.workspace.workspace.id;
const catalog = workspaces.length > 0 ? workspaces : ((await workspacesQuery.refetch()).data ?? []);
const matchingSummary = catalog.find((workspace) => workspace.id === importedId && workspace.configurationState === "configuration_required");
if (!matchingSummary) {
setDiagnostics(["workspace_invalid: Imported bundle can only bootstrap a matching catalog slot"]);
return;
}
const draft: WorkspaceBootstrapDraft = {
workspaceId: importedId,
baseCommit: statusQuery.data?.head ?? EMPTY_COMMIT,
workspace: result.draft.workspace,
updatedAt: new Date().toISOString(),
};
workspaceBootstrapDrafts.save(draft);
setNotice("Imported bootstrap draft saved in this browser. Validate it before creating the descriptor.");
} catch (error) {
const safe = asWorkspaceApiError(error);
setDiagnostics([safe ? `${safe.code}: ${safe.message}` : "workspace_invalid: Workspace bundle could not be imported"]);
} finally {
setTransferring(false);
}
}
function published() {
if (publishRequest) {
workspaceBootstrapDrafts.discard(publishRequest.workspace.workspace.id);
setSelectedId(publishRequest.workspace.workspace.id);
setNotice(`To change this workspace, edit ${publishRequest.workspace.workspace.id}/workspace.yaml, commit/push, then Pull.`);
} else {
setNotice("Workspace created.");
}
setLocalDraft(undefined);
setPublishRequest(undefined);
setDiagnostics([]);
void Promise.all([statusQuery.refetch(), workspacesQuery.refetch()]).then(() => detailQuery.refetch());
}
const titleReady = workspacesQuery.isSuccess || workspacesQuery.isError;
return (
);
}