| "use client";
|
|
|
| import Link from "next/link";
|
| import Image from "next/image";
|
| import type { CliCatalogEntry } from "@/shared/schemas/cliCatalog";
|
| import type { ToolBatchStatus } from "@/shared/types/cliBatchStatus";
|
| import CliStatusBadge from "@/app/(dashboard)/dashboard/cli-code/components/CliStatusBadge";
|
| import { cn } from "@/shared/utils/cn";
|
|
|
| export interface CliToolCardProps {
|
| tool: CliCatalogEntry;
|
| batchStatus: ToolBatchStatus | null;
|
| detailHref: string;
|
| hasActiveProviders: boolean;
|
| }
|
|
|
| export default function CliToolCard({
|
| tool,
|
| batchStatus,
|
| detailHref,
|
| hasActiveProviders,
|
| }: CliToolCardProps) {
|
| const installed = batchStatus?.detection.installed ?? false;
|
| const configStatus = batchStatus?.config.status ?? null;
|
| const version = batchStatus?.detection.version ?? "not found";
|
| const endpoint = batchStatus?.config.endpoint ?? null;
|
|
|
| const showInstallChips = !installed && tool.configType !== "guide";
|
|
|
| const title = (
|
| <div className="flex items-center gap-2.5">
|
| {/* Icon / image */}
|
| {tool.image ? (
|
| <Image
|
| src={tool.image}
|
| alt={tool.name}
|
| width={32}
|
| height={32}
|
| className="rounded-md object-contain flex-shrink-0"
|
| />
|
| ) : (
|
| <span
|
| className="material-symbols-outlined text-[20px] flex-shrink-0"
|
| style={{ color: tool.color }}
|
| aria-hidden="true"
|
| >
|
| {tool.icon ?? "terminal"}
|
| </span>
|
| )}
|
| <div className="min-w-0 flex-1">
|
| <div className="flex items-center gap-2 flex-wrap">
|
| <span className="font-semibold text-text-main text-sm leading-tight truncate">
|
| {tool.name}
|
| </span>
|
| <span className="text-[11px] text-text-muted font-mono bg-black/5 dark:bg-white/5 px-1.5 py-0.5 rounded">
|
| {version}
|
| </span>
|
| </div>
|
| <p className="text-xs text-text-muted line-clamp-1 mt-0.5">{tool.description}</p>
|
| </div>
|
| <span className="material-symbols-outlined text-[18px] text-text-muted flex-shrink-0">
|
| chevron_right
|
| </span>
|
| </div>
|
| );
|
|
|
| return (
|
| <Link
|
| href={detailHref}
|
| className={cn(
|
| "block min-h-[180px]",
|
| "bg-surface border border-black/5 dark:border-white/5 rounded-lg shadow-sm",
|
| "hover:shadow-md hover:border-primary/30 transition-all",
|
| "p-4 flex flex-col gap-3"
|
| )}
|
| >
|
| {/* Header */}
|
| {title}
|
|
|
| {/* Status strip */}
|
| <div className="flex items-center gap-2 flex-wrap">
|
| {/* Detection */}
|
| <span
|
| className={cn(
|
| "inline-flex items-center gap-1 text-[11px] font-medium px-1.5 py-0.5 rounded",
|
| installed
|
| ? "text-green-600 dark:text-green-400"
|
| : "text-zinc-500 dark:text-zinc-400"
|
| )}
|
| >
|
| <span aria-hidden="true">{installed ? "✓" : "✗"}</span>
|
| {installed ? "Detectado" : "Não detectado"}
|
| </span>
|
|
|
| {/* Config status */}
|
| {configStatus && (
|
| <CliStatusBadge
|
| effectiveConfigStatus={configStatus}
|
| batchStatus={null}
|
| lastConfiguredAt={batchStatus?.config.lastConfiguredAt ?? null}
|
| />
|
| )}
|
|
|
| {/* Endpoint */}
|
| {endpoint && (
|
| <span className="text-[10px] text-text-muted font-mono truncate max-w-[140px]">
|
| {endpoint}
|
| </span>
|
| )}
|
| </div>
|
|
|
| {/* Badges row */}
|
| <div className="flex items-center gap-1.5 flex-wrap">
|
| {tool.baseUrlSupport === "partial" && (
|
| <span className="inline-flex items-center gap-1 px-2 py-0.5 text-[11px] font-medium rounded-full bg-amber-500/10 text-amber-600 dark:text-amber-400">
|
| <span aria-hidden="true">⚠</span> Base URL parcial
|
| </span>
|
| )}
|
| {tool.acpSpawnable === true && (
|
| <span className="inline-flex items-center gap-1 px-2 py-0.5 text-[11px] font-medium rounded-full bg-blue-500/10 text-blue-600 dark:text-blue-400">
|
| também ACP
|
| </span>
|
| )}
|
| {showInstallChips && (
|
| <>
|
| <span className="inline-flex items-center gap-1 px-2 py-0.5 text-[11px] font-medium rounded-full bg-black/5 dark:bg-white/5 text-text-muted">
|
| 📋 Manual config
|
| </span>
|
| <span className="inline-flex items-center gap-1 px-2 py-0.5 text-[11px] font-medium rounded-full bg-black/5 dark:bg-white/5 text-text-muted">
|
| ⬇ Install
|
| </span>
|
| </>
|
| )}
|
| </div>
|
|
|
| {}
|
| <div className="mt-auto pt-1 flex items-center justify-between">
|
| <span className="text-xs text-primary font-medium">
|
| {installed ? "Configurar →" : "Como instalar →"}
|
| </span>
|
| {!hasActiveProviders && (
|
| <span
|
| className="text-[10px] text-text-muted italic"
|
| title="Conecte um provider em Providers"
|
| >
|
| Conecte um provider em Providers
|
| </span>
|
| )}
|
| </div>
|
| </Link>
|
| );
|
| }
|
|
|