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
This commit is contained in:
parent
cef656264e
commit
8a392a568b
1 changed files with 49 additions and 2 deletions
|
|
@ -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<string | null>(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)}
|
||||
>
|
||||
<Identity name={agent.name} size="sm" />
|
||||
<span className="text-muted-foreground ml-1 text-xs">
|
||||
({getUIAdapter(agent.adapterType ?? "process").label})
|
||||
</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -432,6 +453,14 @@ export function SkillBrowser() {
|
|||
</Button>
|
||||
<span className="text-sm font-medium">
|
||||
{agents.find((a) => a.id === selectedAgentId)?.name ?? selectedAgentId}
|
||||
{(() => {
|
||||
const a = agents.find((ag) => ag.id === selectedAgentId);
|
||||
return a ? (
|
||||
<span className="text-muted-foreground ml-1 text-xs font-normal">
|
||||
({getUIAdapter(a.adapterType ?? "process").label})
|
||||
</span>
|
||||
) : null;
|
||||
})()}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
|
@ -573,7 +602,10 @@ export function SkillBrowser() {
|
|||
<Dialog
|
||||
open={!!installDialog}
|
||||
onOpenChange={(open) => {
|
||||
if (!open) setInstallDialog(null);
|
||||
if (!open) {
|
||||
setInstallDialog(null);
|
||||
setUnsupportedMessage(null);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<DialogContent>
|
||||
|
|
@ -584,6 +616,15 @@ export function SkillBrowser() {
|
|||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-3">
|
||||
{unsupportedMessage && (
|
||||
<div className="rounded-md border border-destructive/50 bg-destructive/10 p-3 text-sm">
|
||||
<p className="font-medium text-destructive">Cannot install on this agent</p>
|
||||
<p className="text-muted-foreground mt-1">{unsupportedMessage}</p>
|
||||
<Button variant="ghost" size="sm" className="mt-2" onClick={() => setUnsupportedMessage(null)}>
|
||||
Dismiss
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
<div className="space-y-1">
|
||||
{agents.length === 0 && (
|
||||
<p className="text-sm text-muted-foreground">No agents found in this workspace.</p>
|
||||
|
|
@ -597,6 +638,9 @@ export function SkillBrowser() {
|
|||
onClick={() => handleInstallForAgent(agent.id)}
|
||||
>
|
||||
<Identity name={agent.name} size="sm" />
|
||||
<span className="text-muted-foreground ml-1 text-xs">
|
||||
({getUIAdapter(agent.adapterType ?? "process").label})
|
||||
</span>
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -604,7 +648,10 @@ export function SkillBrowser() {
|
|||
<DialogFooter>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setInstallDialog(null)}
|
||||
onClick={() => {
|
||||
setInstallDialog(null);
|
||||
setUnsupportedMessage(null);
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue