kofdai's picture
Deploy NullAI Knowledge System to Spaces
075a2b6 verified
// src/components/TileCard.tsx
import React from 'react';
// Define the TypeScript interfaces corresponding to Pydantic schemas
interface VerificationMark {
verification_type: string;
is_expert_verified: boolean;
expert_orcid_id?: string;
expert_name?: string;
verification_date?: string;
verification_count: number;
}
interface KnowledgeTile {
tile_id: string;
domain_id: string;
topic: string;
content_preview: string;
created_at: string;
updated_at: string;
verification_mark: VerificationMark;
contributor_id?: string;
confidence_score: number;
tags: string[];
}
interface DomainConfig {
domain_id: string;
name: string;
}
interface TileCardProps {
tile: KnowledgeTile;
availableDomains?: DomainConfig[];
onDomainChange?: (tileId: string, newDomainId: string) => void;
}
const TileCard: React.FC<TileCardProps> = ({ tile, availableDomains, onDomainChange }) => {
const getVerificationColor = (type: string) => {
switch (type) {
case 'expert':
case 'multi_expert':
return 'border-green-500';
case 'community':
return 'border-blue-500';
default:
return 'border-gray-500';
}
};
return (
<div className={`panel-section ${getVerificationColor(tile.verification_mark.verification_type)} border-l-4`}>
<div className="flex justify-between items-start">
<h4 className="font-bold text-lg mb-1">{tile.topic}</h4>
{availableDomains && availableDomains.length > 0 && onDomainChange ? (
<select
value={tile.domain_id}
onChange={(e) => onDomainChange(tile.tile_id, e.target.value)}
style={{
fontSize: '12px',
padding: '4px 8px',
backgroundColor: '#2a2a2a',
border: '1px solid #444',
borderRadius: '4px',
color: '#aaa',
cursor: 'pointer'
}}
>
{availableDomains.map(domain => (
<option key={domain.domain_id} value={domain.domain_id}>
{domain.name}
</option>
))}
</select>
) : (
<span className="text-xs text-gray-400 font-mono">{tile.domain_id}</span>
)}
</div>
<p className="text-sm text-gray-300 mb-3">{tile.content_preview}</p>
<div className="text-xs text-gray-500 space-y-1">
<div>
<strong>Confidence:</strong>
<span style={{ color: `hsl(${(tile.confidence_score * 120)}, 100%, 50%)` }}>
{` ${(tile.confidence_score * 100).toFixed(1)}%`}
</span>
</div>
<div>
<strong>Verification:</strong> {tile.verification_mark.verification_type} ({tile.verification_mark.verification_count})
</div>
{tile.verification_mark.is_expert_verified && (
<div>
<strong>Expert:</strong> {tile.verification_mark.expert_name || tile.verification_mark.expert_orcid_id}
</div>
)}
<div>
<strong>Updated:</strong> {new Date(tile.updated_at).toLocaleDateString()}
</div>
</div>
{tile.tags.length > 0 && (
<div className="mt-2 flex flex-wrap gap-1">
{tile.tags.map(tag => (
<span key={tag} className="text-xs bg-gray-700 text-gray-300 px-2 py-1 rounded-full">
{tag}
</span>
))}
</div>
)}
</div>
);
};
export default TileCard;