import { ChevronRight } from 'lucide-react'; import React from 'react'; import { useI18n } from '../../../application/i18n/I18nProvider'; import { cn } from '../../../lib/utils'; import type { VaultToolArtifact } from './vaultToolArtifact'; import { canNavigateVaultArtifact, navigateVaultArtifact, useVaultArtifactNavigation, } from './VaultArtifactNavigationContext'; import { VaultArtifactIcon } from './vaultArtifactPresentation'; interface VaultArtifactCardProps { artifact: VaultToolArtifact; toolName?: string; className?: string; } function getArtifactPresentation( artifact: VaultToolArtifact, t: (key: string, values?: Record) => string, ): { title: string; subtitle?: string; clickable: boolean; } { switch (artifact.kind) { case 'vault.note': return { title: artifact.title, subtitle: artifact.group ?? t('ai.chat.artifact.noteFallback'), clickable: true, }; case 'vault.host': return { title: artifact.label, subtitle: artifact.port ? `${artifact.hostname}:${artifact.port}` : artifact.hostname, clickable: true, }; case 'vault.hosts.batch': { const preview = artifact.preview .slice(0, 2) .map((host) => host.label || host.hostname) .filter(Boolean) .join(', '); return { title: artifact.dryRun ? t('ai.chat.artifact.hostsPreview', { count: artifact.addedCount }) : t('ai.chat.artifact.hostsAdded', { count: artifact.addedCount }), subtitle: preview || t('ai.chat.artifact.openHosts'), clickable: true, }; } case 'vault.summary': return { title: artifact.section === 'notes' ? t('ai.chat.artifact.notesSummary', { count: artifact.count }) : artifact.section === 'hosts' ? t('ai.chat.artifact.hostsSummary', { count: artifact.count }) : artifact.section === 'snippets' ? t('ai.chat.artifact.snippetsSummary', { count: artifact.count }) : t('ai.chat.artifact.scriptsSummary', { count: artifact.count }), subtitle: artifact.section === 'notes' ? t('ai.chat.artifact.openNotes') : artifact.section === 'hosts' ? t('ai.chat.artifact.openHosts') : t('ai.chat.artifact.openSnippets'), clickable: true, }; case 'vault.snippet': return { title: artifact.label, subtitle: artifact.package || t('ai.chat.artifact.snippetFallback'), clickable: true, }; case 'vault.script': return { title: artifact.label, subtitle: artifact.language ? t('ai.chat.artifact.scriptLanguage', { language: artifact.language }) : artifact.package || t('ai.chat.artifact.scriptFallback'), clickable: true, }; case 'vault.snippet.deleted': return { title: t('ai.chat.artifact.snippetDeleted'), subtitle: artifact.snippetId, clickable: false, }; case 'vault.script.deleted': return { title: t('ai.chat.artifact.scriptDeleted'), subtitle: artifact.scriptId, clickable: false, }; case 'vault.snippet.run': return { title: t('ai.chat.artifact.snippetRan'), subtitle: artifact.command || artifact.snippetId, clickable: true, }; case 'vault.script.run': return { title: artifact.status ? t('ai.chat.artifact.scriptRunStatus', { status: artifact.status }) : t('ai.chat.artifact.scriptStarted'), subtitle: artifact.runId, clickable: true, }; case 'vault.script.runs': return { title: t('ai.chat.artifact.scriptRunsSummary', { count: artifact.count }), subtitle: t('ai.chat.artifact.openSnippets'), clickable: true, }; case 'vault.script.action': return { title: artifact.action === 'stop' ? t('ai.chat.artifact.scriptRunStopped') : artifact.action === 'pause' ? t('ai.chat.artifact.scriptRunPaused') : t('ai.chat.artifact.scriptRunResumed'), subtitle: artifact.runId, clickable: false, }; case 'vault.script.reference': return { title: t('ai.chat.artifact.scriptReference'), subtitle: t('ai.chat.artifact.openSnippets'), clickable: true, }; case 'error': return { title: t('ai.chat.artifact.failed'), subtitle: artifact.message, clickable: false, }; default: return { title: '', clickable: false, }; } } export const VaultArtifactCard: React.FC = ({ artifact, toolName, className, }) => { const { t } = useI18n(); const navigation = useVaultArtifactNavigation(); const presentation = getArtifactPresentation(artifact, t); const canNavigate = presentation.clickable && canNavigateVaultArtifact(artifact, navigation); const handleClick = () => { if (!canNavigate || !navigation) return; navigateVaultArtifact(artifact, navigation); }; const content = ( <>
{presentation.title}
{presentation.subtitle && (
{presentation.subtitle}
)}
{canNavigate && ( )} ); if (!canNavigate) { return (
{content}
); } return ( ); };