import React, { useEffect, useState } from "react"; import EnvironmentEditor from "./EnvironmentEditor.jsx"; /** * EnvironmentSelector — Claude-Code-on-Web parity environment dropdown. * * Shows current environment name + gear icon. Gear opens the editor modal. * Fetches environments from /api/environments. */ export default function EnvironmentSelector({ activeEnvId, onEnvChange }) { const [envs, setEnvs] = useState([]); const [editorOpen, setEditorOpen] = useState(false); const [editingEnv, setEditingEnv] = useState(null); const fetchEnvs = async () => { try { const res = await fetch("/api/environments", { cache: "no-cache" }); if (!res.ok) return; const data = await res.json(); setEnvs(data.environments || []); } catch (err) { console.warn("Failed to fetch environments:", err); } }; useEffect(() => { fetchEnvs(); }, []); const activeEnv = envs.find((e) => e.id === activeEnvId) || envs[0] || { name: "Default", id: "default" }; const handleSave = async (config) => { try { const method = config.id ? "PUT" : "POST"; const url = config.id ? `/api/environments/${config.id}` : "/api/environments"; await fetch(url, { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(config), }); await fetchEnvs(); setEditorOpen(false); setEditingEnv(null); } catch (err) { console.warn("Failed to save environment:", err); } }; const handleDelete = async (envId) => { try { await fetch(`/api/environments/${envId}`, { method: "DELETE" }); await fetchEnvs(); if (activeEnvId === envId) { onEnvChange?.(null); } } catch (err) { console.warn("Failed to delete environment:", err); } }; return (
ENVIRONMENT
{/* Env selector */} {/* Network badge */} {activeEnv.network_access || "limited"}
{/* Gear icon */} {/* Add new */}
{/* Editor modal */} {editorOpen && ( handleDelete(editingEnv.id) : null} onClose={() => { setEditorOpen(false); setEditingEnv(null); }} /> )}
); } const styles = { container: { padding: "10px 14px", }, label: { fontSize: 10, fontWeight: 700, letterSpacing: "0.08em", color: "#71717A", textTransform: "uppercase", marginBottom: 6, }, row: { display: "flex", alignItems: "center", gap: 6, }, envCard: { flex: 1, display: "flex", alignItems: "center", gap: 8, padding: "4px 8px", borderRadius: 6, border: "1px solid #27272A", backgroundColor: "#18181B", minWidth: 0, }, select: { flex: 1, background: "transparent", border: "none", color: "#E4E4E7", fontSize: 12, fontWeight: 500, outline: "none", cursor: "pointer", minWidth: 0, }, networkBadge: { fontSize: 9, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.04em", flexShrink: 0, }, gearBtn: { width: 28, height: 28, borderRadius: 6, border: "1px solid #27272A", background: "transparent", color: "#71717A", cursor: "pointer", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 14, flexShrink: 0, }, };