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-fns for 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
  • AssistantDisplay type for data structure
  • RelativeTime component for timestamp display
  • FirebaseService for data operations
  • Various UI primitives from @/components/ui/