EMISSARY_LIST_COMPONENT.md
Component documentation for the EmissaryList AI assistant listing interface.
Overview
The EmissaryList component provides a comprehensive interface for displaying, managing, and interacting with AI assistants (called “Emissaries”). It supports both grid and table view modes, sorting options, and various assistant management actions.
Component Location
- File:
src/components/EmissaryList.tsx - Type: Data Display Component
- Framework: React with TypeScript
Features
- Dual View Modes: Grid cards and table list layouts
- Advanced Sorting: By last accessed, creation date, name, or usage count
- Message Integration: Shows last messages and conversation counts
- Document Tracking: Displays attached document counts
- Interactive Actions: Edit, duplicate, delete, and view assistants
- Safe Timestamp Handling: Robust date/time processing with error handling
- Responsive Design: Mobile-optimized with horizontal scroll for tables
- Real-time Updates: Integrates with Firebase for live message data
Props Interface
interface EmissaryListProps {
bots: AssistantDisplay[]; // Array of assistants to display
showEditButton?: boolean; // Show edit action button
onEdit?: (bot: AssistantDisplay) => void; // Edit callback
onView?: (bot: AssistantDisplay) => void; // View/chat callback
onDuplicate?: (bot: AssistantDisplay) => void; // Duplicate callback
onDelete?: (bot: AssistantDisplay) => void; // Delete callback
}
View Modes
Grid View
Displays assistants as cards with detailed information:
// Grid view with rich cards showing avatars, metadata, and tools
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{botsWithMessages.map((bot) => (
<Card key={bot.assistantId} className="flex flex-col min-w-0">
{/* Card content with avatar, name, stats, and actions */}
</Card>
))}
</div>
Table View
Compact table layout for efficient browsing:
// Table view with horizontal scroll support
<div className="rounded-md border overflow-hidden">
<table className="w-full min-w-[650px]">
<thead>
<tr>
<th>Assistant</th>
<th>Last Message</th>
<th>Messages</th>
<th>Docs</th>
<th>Last Used</th>
<th>Actions</th>
</tr>
</thead>
{/* Table body with assistant data */}
</table>
</div>
Sorting Options
The component supports four sorting modes:
type SortOption = 'lastAccessed' | 'created' | 'name' | 'usage';
const sortBots = (botsToSort: AssistantWithMessages[], sortOption: SortOption) => {
return [...botsToSort].sort((a, b) => {
switch (sortOption) {
case 'lastAccessed':
return bLastAccessed - aLastAccessed; // Most recent first
case 'created':
return bCreated - aCreated; // Newest first
case 'name':
return a.name.localeCompare(b.name); // Alphabetical
case 'usage':
return (b.usageCount || 0) - (a.usageCount || 0); // Most used first
}
});
};
Usage Examples
Basic Implementation
import { EmissaryList } from '@/components/EmissaryList';
function AssistantManager({ assistants }) {
const handleEdit = (bot) => {
// Navigate to edit form
router.push(`/admin/edit/${bot.assistantId}`);
};
const handleView = (bot) => {
// Navigate to chat interface
router.push(`/assistant/${bot.assistantId}`);
};
return (
<EmissaryList
bots={assistants}
showEditButton={true}
onEdit={handleEdit}
onView={handleView}
onDuplicate={handleDuplicate}
onDelete={handleDelete}
/>
);
}
Read-Only Display
// Display without edit/delete actions
<EmissaryList
bots={publicAssistants}
showEditButton={false}
onView={handleView}
/>
Message Integration
The component fetches and displays message data for each assistant:
// Fetches last message and count for each assistant
const fetchMessages = async () => {
const botsWithMessagesData = await Promise.all(
processedBots.map(async (bot) => {
const messages = await FirebaseService.getMessages(bot.assistantId);
return {
...bot,
lastMessage: messages[messages.length - 1],
messageCount: messages.length
};
})
);
};
Timestamp Safety
The component includes robust timestamp handling to prevent errors:
const safeExtractTimestamp = (date: Date | undefined | null): TimestampInfo => {
try {
if (!date) return { valid: false, value: null, displayValue: 'undefined/null' };
const timestamp = date.getTime();
if (isNaN(timestamp)) return { valid: false, value: null, displayValue: 'Invalid Date' };
return { valid: true, value: timestamp, displayValue: date.toISOString() };
} catch (e) {
return { valid: false, value: null, displayValue: 'Error: ' + e.message };
}
};
Empty State
When no assistants are available:
if (bots.length === 0) {
return (
<Card>
<CardContent className="p-8 text-center">
<p className="text-muted-foreground">You don't have any assistants yet.</p>
<Link href="/admin">
<Button>Create Assistant</Button>
</Link>
</CardContent>
</Card>
);
}
Delete Confirmation
Includes a confirmation dialog for delete operations:
<AlertDialog open={deleteConfirmOpen} onOpenChange={setDeleteConfirmOpen}>
<AlertDialogContent>
<AlertDialogTitle>Delete Assistant</AlertDialogTitle>
<AlertDialogDescription>
Are you sure you want to delete "{botToDelete?.name}"?
This action cannot be undone.
</AlertDialogDescription>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={handleDeleteConfirm}>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
Dependencies
Core Libraries
- React hooks for state management
- Firestore integration via
FirebaseService date-fnsfor relative time formatting
UI Components
- Card components for grid layout
- Alert dialog for confirmations
- Tooltips for additional information
- Badges for metadata display
Icons
- Lucide React icons for actions and metadata
- Custom avatar components
Performance Considerations
- Memoized sorting to prevent unnecessary re-computation
- Safe error handling to prevent component crashes
- Efficient message fetching with Promise.all
- Proper loading states during data operations
Responsive Design
- Grid layout adapts to screen size (1-3 columns)
- Table view with horizontal scroll on mobile
- Mobile-optimized button layouts
- Tooltip placement adjustments
Related Components
AssistantDisplaytype for data structureRelativeTimecomponent for timestamp displayFirebaseServicefor data operations- Various UI primitives from
@/components/ui/