From 46a448eb338d2314069311437b4ac584bff9e989 Mon Sep 17 00:00:00 2001 From: Mikkel Georgsen Date: Wed, 1 Apr 2026 12:03:11 +0200 Subject: [PATCH] feat(20-02): add adapter labels and unsupported install guard to SkillBrowser - Import getUIAdapter and resolveAdapterSkillConfig/listAdapterSkillConfigs - Show adapter type label in parentheses next to agent name in Installed tab selector - Show adapter type label in install dialog agent list - Guard handleInstallForAgent: show unsupportedMessage if adapter does not support install - Dismissible error alert in install dialog for unsupported adapter attempts - Clear unsupportedMessage on dialog open/close - Compute COMPATIBLE_ADAPTER_LABELS at module level for Task 2 --- ui/src/pages/SkillBrowser.tsx | 51 +++++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/ui/src/pages/SkillBrowser.tsx b/ui/src/pages/SkillBrowser.tsx index e5f4bc82..f8cbaf31 100644 --- a/ui/src/pages/SkillBrowser.tsx +++ b/ui/src/pages/SkillBrowser.tsx @@ -38,6 +38,13 @@ import { PageTabBar } from "@/components/PageTabBar"; import { PageSkeleton } from "@/components/PageSkeleton"; import { Identity } from "@/components/Identity"; import { cn } from "@/lib/utils"; +import { getUIAdapter } from "@/adapters"; +import { resolveAdapterSkillConfig, listAdapterSkillConfigs } from "@paperclipai/adapter-utils"; + +// Compute compatible adapter labels once at module level (used by Browse/Trending SkillCards) +const COMPATIBLE_ADAPTER_LABELS = listAdapterSkillConfigs() + .filter((c) => c.supportsInstall) + .map((c) => getUIAdapter(c.adapterType).label); type SortBy = "rating" | "name" | "recent"; @@ -62,6 +69,7 @@ export function SkillBrowser() { // Dialog state const [installDialog, setInstallDialog] = useState<{ skillId: string; isUpdate?: boolean } | null>(null); const [uninstallDialog, setUninstallDialog] = useState<{ skillId: string; agentId: string } | null>(null); + const [unsupportedMessage, setUnsupportedMessage] = useState(null); useEffect(() => { setBreadcrumbs([ @@ -253,6 +261,16 @@ export function SkillBrowser() { const handleInstallForAgent = (agentId: string) => { if (!installDialog) return; + const agent = agents.find((a) => a.id === agentId); + if (agent) { + const cfg = resolveAdapterSkillConfig(agent.adapterType ?? "process"); + if (!cfg.supportsInstall) { + setUnsupportedMessage( + cfg.unsupportedReason ?? "This adapter does not support skill installation." + ); + return; + } + } if (installDialog.isUpdate) { updateMutation.mutate({ skillId: installDialog.skillId, agentId }); } else { @@ -413,6 +431,9 @@ export function SkillBrowser() { onClick={() => setSelectedAgentId(agent.id)} > + + ({getUIAdapter(agent.adapterType ?? "process").label}) + ))} @@ -432,6 +453,14 @@ export function SkillBrowser() { {agents.find((a) => a.id === selectedAgentId)?.name ?? selectedAgentId} + {(() => { + const a = agents.find((ag) => ag.id === selectedAgentId); + return a ? ( + + ({getUIAdapter(a.adapterType ?? "process").label}) + + ) : null; + })()} @@ -573,7 +602,10 @@ export function SkillBrowser() { { - if (!open) setInstallDialog(null); + if (!open) { + setInstallDialog(null); + setUnsupportedMessage(null); + } }} > @@ -584,6 +616,15 @@ export function SkillBrowser() {
+ {unsupportedMessage && ( +
+

Cannot install on this agent

+

{unsupportedMessage}

+ +
+ )}
{agents.length === 0 && (

No agents found in this workspace.

@@ -597,6 +638,9 @@ export function SkillBrowser() { onClick={() => handleInstallForAgent(agent.id)} > + + ({getUIAdapter(agent.adapterType ?? "process").label}) + ))}
@@ -604,7 +648,10 @@ export function SkillBrowser() {