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:
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
))}
|
||||
|
||||
@@ -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",
|
||||
};
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user