ui: add Cursor adapter option and mark non-functional adapters as Coming Soon

Only Claude Code and Codex are selectable. OpenClaw, Cursor, Shell Command,
and HTTP Webhook are shown as disabled with "Coming soon" across all adapter
selection UIs: onboarding wizard, agent config form, and invite landing page.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dotta
2026-03-03 11:29:34 -06:00
parent 5f37b70be5
commit 2ac47ff4cb
5 changed files with 59 additions and 17 deletions

View File

@@ -801,6 +801,18 @@ function AdapterEnvironmentResult({ result }: { result: AdapterEnvironmentTestRe
/* ---- Internal sub-components ---- */
const ENABLED_ADAPTER_TYPES = new Set(["claude_local", "codex_local"]);
/** Display list includes all real adapter types plus UI-only coming-soon entries. */
const ADAPTER_DISPLAY_LIST: { value: string; label: string; comingSoon: boolean }[] = [
...AGENT_ADAPTER_TYPES.map((t) => ({
value: t,
label: adapterLabels[t] ?? t,
comingSoon: !ENABLED_ADAPTER_TYPES.has(t),
})),
{ value: "cursor", label: "Cursor", comingSoon: true },
];
function AdapterTypeDropdown({
value,
onChange,
@@ -817,16 +829,25 @@ function AdapterTypeDropdown({
</button>
</PopoverTrigger>
<PopoverContent className="w-[var(--radix-popover-trigger-width)] p-1" align="start">
{AGENT_ADAPTER_TYPES.map((t) => (
{ADAPTER_DISPLAY_LIST.map((item) => (
<button
key={t}
key={item.value}
disabled={item.comingSoon}
className={cn(
"flex items-center gap-2 w-full px-2 py-1.5 text-sm rounded hover:bg-accent/50",
t === value && "bg-accent",
"flex items-center justify-between w-full px-2 py-1.5 text-sm rounded",
item.comingSoon
? "opacity-40 cursor-not-allowed"
: "hover:bg-accent/50",
item.value === value && !item.comingSoon && "bg-accent",
)}
onClick={() => onChange(t)}
onClick={() => {
if (!item.comingSoon) onChange(item.value);
}}
>
{adapterLabels[t] ?? t}
<span>{item.label}</span>
{item.comingSoon && (
<span className="text-[10px] text-muted-foreground">Coming soon</span>
)}
</button>
))}
</PopoverContent>

View File

@@ -18,6 +18,7 @@ const adapterLabels: Record<string, string> = {
claude_local: "Claude (local)",
codex_local: "Codex (local)",
openclaw: "OpenClaw",
cursor: "Cursor",
process: "Process",
http: "HTTP",
};

View File

@@ -31,6 +31,7 @@ import {
Terminal,
Globe,
Sparkles,
MousePointer2,
Check,
Loader2,
FolderOpen,
@@ -383,34 +384,49 @@ export function OnboardingWizard() {
label: "OpenClaw",
icon: Bot,
desc: "Notify OpenClaw webhook",
comingSoon: true,
},
{
value: "cursor" as const,
label: "Cursor",
icon: MousePointer2,
desc: "Cursor AI agent",
comingSoon: true,
},
{
value: "process" as const,
label: "Shell Command",
icon: Terminal,
desc: "Run a process",
comingSoon: true,
},
{
value: "http" as const,
label: "HTTP Webhook",
icon: Globe,
desc: "Call an endpoint",
comingSoon: true,
},
] as const).map((opt) => (
]).map((opt) => (
<button
key={opt.value}
disabled={!!opt.comingSoon}
className={cn(
"flex flex-col items-center gap-1.5 rounded-md border p-3 text-xs transition-colors",
adapterType === opt.value
? "border-foreground bg-accent"
: "border-border hover:bg-accent/50"
"flex flex-col items-center gap-1.5 rounded-md border p-3 text-xs transition-colors relative",
opt.comingSoon
? "border-border opacity-40 cursor-not-allowed"
: adapterType === opt.value
? "border-foreground bg-accent"
: "border-border hover:bg-accent/50"
)}
onClick={() => setAdapterType(opt.value)}
onClick={() => {
if (!opt.comingSoon) setAdapterType(opt.value as AdapterType);
}}
>
<opt.icon className="h-4 w-4" />
<span className="font-medium">{opt.label}</span>
<span className="text-muted-foreground text-[10px]">
{opt.desc}
{opt.comingSoon ? "Coming soon" : opt.desc}
</span>
</button>
))}

View File

@@ -53,6 +53,7 @@ export const adapterLabels: Record<string, string> = {
claude_local: "Claude (local)",
codex_local: "Codex (local)",
openclaw: "OpenClaw",
cursor: "Cursor",
process: "Process",
http: "HTTP",
};

View File

@@ -15,14 +15,17 @@ const joinAdapterOptions: AgentAdapterType[] = [
...AGENT_ADAPTER_TYPES.filter((type): type is Exclude<AgentAdapterType, "openclaw"> => type !== "openclaw"),
];
const adapterLabels: Record<AgentAdapterType, string> = {
const adapterLabels: Record<string, string> = {
claude_local: "Claude (local)",
codex_local: "Codex (local)",
openclaw: "OpenClaw",
cursor: "Cursor",
process: "Process",
http: "HTTP",
};
const ENABLED_INVITE_ADAPTERS = new Set(["claude_local", "codex_local"]);
function dateTime(value: string) {
return new Date(value).toLocaleString();
}
@@ -42,7 +45,7 @@ export function InviteLandingPage() {
const token = (params.token ?? "").trim();
const [joinType, setJoinType] = useState<JoinType>("human");
const [agentName, setAgentName] = useState("");
const [adapterType, setAdapterType] = useState<AgentAdapterType>("openclaw");
const [adapterType, setAdapterType] = useState<AgentAdapterType>("claude_local");
const [capabilities, setCapabilities] = useState("");
const [result, setResult] = useState<{ kind: "bootstrap" | "join"; payload: unknown } | null>(null);
const [error, setError] = useState<string | null>(null);
@@ -255,8 +258,8 @@ export function InviteLandingPage() {
onChange={(event) => setAdapterType(event.target.value as AgentAdapterType)}
>
{joinAdapterOptions.map((type) => (
<option key={type} value={type}>
{adapterLabels[type]}
<option key={type} value={type} disabled={!ENABLED_INVITE_ADAPTERS.has(type)}>
{adapterLabels[type]}{!ENABLED_INVITE_ADAPTERS.has(type) ? " (Coming soon)" : ""}
</option>
))}
</select>