UserTasksDebuggerTab.tsx31.1 KBView on GitHub
import { Check, Copy, ChevronDown, ChevronRight, Search, Calendar } from 'lucide-react';
import type { TaskDateKey } from '@/modules/userTasks/slice/userTasksSlice';
import { motion, AnimatePresence } from 'motion/react';
import React, { useState, useMemo } from 'react';
import { useCedarStore } from '@/modules/store';
import { cn } from '@/styles/stylingUtils';
import { JsonTreeView } from './JsonTreeView';

interface UserTasksTabProps {
  tasks: Record<string, any>;
  scheduledExecutions: Record<string, any>;
  onCopy: (text: string, id: string) => void;
  copiedId: string | null;
}

// Date key labels for display
const DATE_KEY_LABELS: Record<TaskDateKey, string> = {
  previous: 'Previous (< -3 days)',
  '-3': '3 Days Ago',
  '-2': '2 Days Ago',
  '-1': 'Yesterday',
  today: 'Today',
  '+1': 'Tomorrow',
  '+2': 'In 2 Days',
  '+3': 'In 3 Days',
  future: 'Future (> +3 days)',
};

const DATE_KEY_ORDER: TaskDateKey[] = [
  'previous',
  '-3',
  '-2',
  '-1',
  'today',
  '+1',
  '+2',
  '+3',
  'future',
];

// Component to display tasks organized by date
const TasksByDateComponent = ({
  onCopy,
  copiedId,
}: {
  onCopy: (text: string, id: string) => void;
  copiedId: string | null;
}) => {
  const taskIdsByDateKey=[redacted] => state.taskIdsByDateKey);
  const executionIdsByDateKey=[redacted] => state.executionIdsByDateKey);
  const tasksViewSelectedDate = useCedarStore((state) => state.tasksViewSelectedDate);
  const tasks = useCedarStore((state) => state.tasks);
  const scheduledExecutions = useCedarStore((state) => state.scheduledExecutions);

  const [isSectionExpanded, setIsSectionExpanded] = useState(true);
  const [expandedDateKeys, setExpandedDateKeys] = useState<Set<TaskDateKey>>(new Set(['today']));
  const [expandedTasks, setExpandedTasks] = useState<Set<string>>(new Set());

  const safeStringify = (obj: unknown, indent = 2): string => {
    try {
      return JSON.stringify(obj, null, indent);
    } catch (error) {
      return `[Error serializing object: ${error instanceof Error ? error.message : 'Unknown error'}]`;
    }
  };

  const toggleDateKey=[redacted] TaskDateKey) => {
    setExpandedDateKeys((prev) => {
      const next = new Set(prev);
      if (next.has(dateKey)) {
        next.delete(dateKey);
      } else {
        next.add(dateKey);
      }
      return next;
    });
  };

  const toggleTask = (taskId: string) => {
    setExpandedTasks((prev) => {
      const next = new Set(prev);
      if (next.has(taskId)) {
        next.delete(taskId);
      } else {
        next.add(taskId);
      }
      return next;
    });
  };

  // Calculate total items across all date keys
  const totalTasks = DATE_KEY_ORDER.reduce(
    (sum, key) => sum + (taskIdsByDateKey[key]?.length || 0),
    0,
  );
  const totalExecutions = DATE_KEY_ORDER.reduce(
    (sum, key) => sum + (executionIdsByDateKey[key]?.length || 0),
    0,
  );

  // Get selected date key based on tasksViewSelectedDate
  const getSelectedDateKey = (): TaskDateKey | null => {
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    const selected = new Date(tasksViewSelectedDate);
    selected.setHours(0, 0, 0, 0);

    const diffDays = Math.round((selected.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));

    if (diffDays < -3) return 'previous';
    if (diffDays === -3) return '-3';
    if (diffDays === -2) return '-2';
    if (diffDays === -1) return '-1';
    if (diffDays === 0) return 'today';
    if (diffDays === 1) return '+1';
    if (diffDays === 2) return '+2';
    if (diffDays === 3) return '+3';
    if (diffDays > 3) return 'future';
    return null;
  };

  const selectedDateKey=[redacted];

  return (
    <div className="border-b border-gray-200 bg-blue-50/50 dark:border-gray-700 dark:bg-blue-950/20">
      <div
        className="flex cursor-pointer items-center justify-between p-3 transition-colors hover:bg-blue-100/50 dark:hover:bg-blue-900/30"
        onClick={() => setIsSectionExpanded(!isSectionExpanded)}
      >
        <div className="flex items-center gap-2">
          <Calendar className="h-4 w-4 text-blue-600 dark:text-blue-400" />
          <span className="font-medium text-blue-900 dark:text-blue-100">
            Tasks By Date ({totalTasks} tasks, {totalExecutions} executions)
          </span>
        </div>
        <div className="flex items-center gap-1">
          <button
            onClick={(e) => {
              e.stopPropagation();
              onCopy(
                safeStringify({
                  taskIdsByDateKey,
                  executionIdsByDateKey,
                  tasksViewSelectedDate: tasksViewSelectedDate.toISOString(),
                }),
                'tasksByDate',
              );
            }}
            className="rounded p-0.5 transition-colors hover:bg-blue-200 dark:hover:bg-blue-800"
          >
            {copiedId === 'tasksByDate' ? (
              <Check className="h-3 w-3 text-green-600" />
            ) : (
              <Copy className="h-3 w-3" />
            )}
          </button>
          {isSectionExpanded ? (
            <ChevronDown className="h-3 w-3" />
          ) : (
            <ChevronRight className="h-3 w-3" />
          )}
        </div>
      </div>

      <AnimatePresence>
        {isSectionExpanded && (
          <motion.div
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: 'auto', opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            transition={{ duration: 0.2 }}
            className="overflow-hidden"
          >
            <div className="max-h-[500px] space-y-3 overflow-y-auto p-3 pt-0">
              {/* Selected Date Info */}
              <div className="rounded bg-white p-2 dark:bg-gray-800">
                <div className="mb-1 text-xs font-semibold text-blue-700 dark:text-blue-300">
                  Selected Date:
                </div>
                <div className="flex items-center gap-2">
                  <span className="font-mono text-xs">
                    {tasksViewSelectedDate.toLocaleDateString()}
                  </span>
                  {selectedDateKey && (
                    <span className="rounded bg-blue-100 px-1.5 py-0.5 text-xs text-blue-800 dark:bg-blue-900 dark:text-blue-200">
                      {DATE_KEY_LABELS[selectedDateKey]}
                    </span>
                  )}
                </div>
              </div>

              {/* Date Key Breakdown */}
              <div className="space-y-2">
                {DATE_KEY_ORDER.map((dateKey) => {
                  const taskIds = taskIdsByDateKey[dateKey] || [];
                  const executionIds = executionIdsByDateKey[dateKey] || [];
                  const isExpanded = expandedDateKeys.has(dateKey);
                  const isSelected = dateKey === selectedDateKey;
                  const hasItems = taskIds.length > 0 || executionIds.length > 0;

                  return (
                    <div
                      key=[redacted]
                      className={cn(
                        'rounded border',
                        isSelected
                          ? 'border-blue-400 bg-blue-100 dark:border-blue-600 dark:bg-blue-900/50'
                          : 'border-gray-200 bg-white dark:border-gray-600 dark:bg-gray-800',
                      )}
                    >
                      <div
                        className={cn(
                          'flex cursor-pointer items-center justify-between p-2',
                          isExpanded ? 'rounded-t' : 'rounded',
                          isSelected
                            ? 'hover:bg-blue-200/50 dark:hover:bg-blue-800/50'
                            : 'hover:bg-gray-50 dark:hover:bg-gray-700',
                        )}
                        onClick={() => toggleDateKey(dateKey)}
                      >
                        <div className="flex items-center gap-2">
                          {isExpanded ? (
                            <ChevronDown className="h-3 w-3" />
                          ) : (
                            <ChevronRight className="h-3 w-3" />
                          )}
                          <span
                            className={cn(
                              'text-xs font-medium',
                              isSelected ? 'text-blue-800 dark:text-blue-200' : '',
                            )}
                          >
                            {DATE_KEY_LABELS[dateKey]}
                          </span>
                          <span className="rounded bg-gray-200 px-1.5 py-0.5 text-xs text-gray-700 dark:bg-gray-700 dark:text-gray-300">
                            {taskIds.length} tasks
                          </span>
                          {executionIds.length > 0 && (
                            <span className="rounded bg-orange-100 px-1.5 py-0.5 text-xs text-orange-800 dark:bg-orange-900 dark:text-orange-200">
                              {executionIds.length} executions
                            </span>
                          )}
                        </div>
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            onCopy(safeStringify({ taskIds, executionIds }), `dateKey-${dateKey}`);
                          }}
                          className="rounded p-0.5 hover:bg-gray-200 dark:hover:bg-gray-600"
                        >
                          {copiedId === `dateKey-${dateKey}` ? (
                            <Check className="h-3 w-3 text-green-600" />
                          ) : (
                            <Copy className="h-3 w-3" />
                          )}
                        </button>
                      </div>

                      <AnimatePresence>
                        {isExpanded && hasItems && (
                          <motion.div
                            initial={{ height: 0, opacity: 0 }}
                            animate={{ height: 'auto', opacity: 1 }}
                            exit={{ height: 0, opacity: 0 }}
                            transition={{ duration: 0.15 }}
                            className="overflow-hidden"
                          >
                            <div
                              className="space-y-2 border-t border-gray-200 p-2 dark:border-gray-600"
                              onClick={(e) => e.stopPropagation()}
                            >
                              {/* Tasks */}
                              {taskIds.map((taskId) => {
                                const task = tasks[taskId];
                                const isTaskExpanded = expandedTasks.has(taskId);
                                return (
                                  <div
                                    key=[redacted]
                                    className="rounded border border-gray-200 bg-gray-50 dark:border-gray-600 dark:bg-gray-700"
                                  >
                                    <div
                                      className={cn(
                                        'flex cursor-pointer items-center justify-between p-1.5 hover:bg-gray-100 dark:hover:bg-gray-600',
                                        isTaskExpanded ? 'rounded-t' : 'rounded',
                                      )}
                                      onClick={() => toggleTask(taskId)}
                                    >
                                      <div className="flex flex-1 flex-col gap-0.5">
                                        <div className="flex items-center gap-2">
                                          {isTaskExpanded ? (
                                            <ChevronDown className="h-2.5 w-2.5" />
                                          ) : (
                                            <ChevronRight className="h-2.5 w-2.5" />
                                          )}
                                          <span className="font-mono text-[10px]">
                                            {taskId.slice(0, 8)}...
                                          </span>
                                          {task?.taskType && (
                                            <span className="rounded bg-purple-100 px-1 py-0.5 text-[10px] text-purple-800 dark:bg-purple-900 dark:text-purple-200">
                                              {task.taskType}
                                            </span>
                                          )}
                                          {task?.taskOutput?.kind && (
                                            <span className="rounded bg-green-100 px-1 py-0.5 text-[10px] text-green-800 dark:bg-green-900 dark:text-green-200">
                                              {task.taskOutput.kind}
                                            </span>
                                          )}
                                        </div>
                                        {task?.description && (
                                          <span className="ml-5 max-w-[300px] truncate text-[10px] text-gray-600 dark:text-gray-400">
                                            {task.description}
                                          </span>
                                        )}
                                        {task?.dueDate && (
                                          <span className="ml-5 text-[10px] text-gray-500 dark:text-gray-500">
                                            Due: {new Date(task.dueDate).toLocaleString()}
                                          </span>
                                        )}
                                      </div>
                                      <button
                                        onClick={(e) => {
                                          e.stopPropagation();
                                          onCopy(safeStringify(task), taskId);
                                        }}
                                        className="rounded p-0.5 hover:bg-gray-200 dark:hover:bg-gray-500"
                                      >
                                        {copiedId === taskId ? (
                                          <Check className="h-2.5 w-2.5 text-green-600" />
                                        ) : (
                                          <Copy className="h-2.5 w-2.5" />
                                        )}
                                      </button>
                                    </div>
                                    <AnimatePresence>
                                      {isTaskExpanded && (
                                        <motion.div
                                          initial={{ height: 0, opacity: 0 }}
                                          animate={{ height: 'auto', opacity: 1 }}
                                          exit={{ height: 0, opacity: 0 }}
                                          transition={{ duration: 0.1 }}
                                          className="overflow-hidden"
                                        >
                                          <div
                                            className="border-t border-gray-200 p-1.5 dark:border-gray-600"
                                            onClick={(e) => e.stopPropagation()}
                                          >
                                            <JsonTreeView data={task} onCopy={onCopy} copiedId={copiedId} defaultExpandDepth={2} className="max-h-48" />
                                          </div>
                                        </motion.div>
                                      )}
                                    </AnimatePresence>
                                  </div>
                                );
                              })}

                              {/* Executions */}
                              {executionIds.map((execId) => {
                                const execution = scheduledExecutions[execId];
                                return (
                                  <div
                                    key=[redacted]
                                    className="flex items-center gap-2 rounded border border-orange-200 bg-orange-50 p-1.5 dark:border-orange-800 dark:bg-orange-900/30"
                                  >
                                    <span className="font-mono text-[10px]">
                                      {execId.slice(0, 8)}...
                                    </span>
                                    {execution?.scheduledFor && (
                                      <span className="text-[10px] text-orange-700 dark:text-orange-300">
                                        {new Date(execution.scheduledFor).toLocaleString()}
                                      </span>
                                    )}
                                    <button
                                      onClick={(e) => {
                                        e.stopPropagation();
                                        onCopy(safeStringify(execution), execId);
                                      }}
                                      className="ml-auto rounded p-0.5 hover:bg-orange-200 dark:hover:bg-orange-800"
                                    >
                                      {copiedId === execId ? (
                                        <Check className="h-2.5 w-2.5 text-green-600" />
                                      ) : (
                                        <Copy className="h-2.5 w-2.5" />
                                      )}
                                    </button>
                                  </div>
                                );
                              })}
                            </div>
                          </motion.div>
                        )}
                      </AnimatePresence>
                    </div>
                  );
                })}
              </div>
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
};

export const UserTasksDebuggerTab: React.FC<UserTasksTabProps> = ({
  tasks,
  scheduledExecutions,
  onCopy,
  copiedId,
}) => {
  const [expandedRawTasks, setExpandedRawTasks] = useState<Set<string>>(new Set());
  const [expandedRawExecutions, setExpandedRawExecutions] = useState<Set<string>>(new Set());
  const [searchQuery, setSearchQuery] = useState('');

  const taskEntries = useMemo(() => Object.entries(tasks), [tasks]);
  const executionEntries = useMemo(
    () => Object.entries(scheduledExecutions),
    [scheduledExecutions],
  );

  const filteredTasks = useMemo(() => {
    if (!searchQuery) return taskEntries;

    const query = searchQuery.toLowerCase();
    return taskEntries.filter(([taskId, task]) => {
      if (taskId.toLowerCase().includes(query)) return true;
      if (task?.conversationId?.toLowerCase().includes(query)) return true;
      try {
        const jsonString = JSON.stringify(task).toLowerCase();
        if (jsonString.includes(query)) return true;
      } catch {}
      return false;
    });
  }, [taskEntries, searchQuery]);

  const filteredExecutions = useMemo(() => {
    if (!searchQuery) return executionEntries;

    const query = searchQuery.toLowerCase();
    return executionEntries.filter(([runId, execution]) => {
      if (runId.toLowerCase().includes(query)) return true;
      if (execution?.conversationId?.toLowerCase().includes(query)) return true;
      if (execution?.threadId?.toLowerCase().includes(query)) return true;
      try {
        const jsonString = JSON.stringify(execution).toLowerCase();
        if (jsonString.includes(query)) return true;
      } catch {}
      return false;
    });
  }, [executionEntries, searchQuery]);

  const toggleRawTask = (taskId: string) => {
    setExpandedRawTasks((prev) => {
      const next = new Set(prev);
      if (next.has(taskId)) {
        next.delete(taskId);
      } else {
        next.add(taskId);
      }
      return next;
    });
  };

  const toggleRawExecution = (runId: string) => {
    setExpandedRawExecutions((prev) => {
      const next = new Set(prev);
      if (next.has(runId)) {
        next.delete(runId);
      } else {
        next.add(runId);
      }
      return next;
    });
  };

  const safeStringify = (obj: unknown, indent = 2): string => {
    try {
      return JSON.stringify(obj, null, indent);
    } catch (error) {
      return `[Error serializing: ${error instanceof Error ? error.message : 'Unknown'}]`;
    }
  };

  return (
    <div className="flex h-full flex-col">
      {/* Tasks By Date Section */}
      <TasksByDateComponent onCopy={onCopy} copiedId={copiedId} />

      {/* Search Bar */}
      <div className="border-b border-gray-200 p-2 dark:border-gray-700">
        <div className="relative">
          <Search className="absolute left-2 top-1/2 h-3 w-3 -translate-y-1/2 text-gray-400" />
          <input
            type="text"
            placeholder="Search tasks and executions..."
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            className="w-full rounded border border-gray-300 bg-white py-1 pl-7 pr-2 text-xs placeholder:text-gray-400 focus:border-blue-500 focus:outline-none dark:border-gray-600 dark:bg-gray-800 dark:text-white"
          />
        </div>
      </div>

      {/* Content */}
      <div className="flex-1 space-y-3 overflow-y-auto p-2">
        {/* Tasks Section */}
        <div>
          <h3 className="mb-2 text-xs font-semibold text-gray-600 dark:text-gray-400">
            Tasks ({filteredTasks.length})
          </h3>
          {filteredTasks.length === 0 ? (
            <div className="py-4 text-center text-xs text-gray-500">
              {searchQuery ? 'No tasks match' : 'No tasks'}
            </div>
          ) : (
            <div className="space-y-2">
              {filteredTasks.map(([taskId, task]) => {
                const isExpanded = expandedRawTasks.has(taskId);
                return (
                  <div
                    key=[redacted]
                    className="rounded-lg border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-950"
                  >
                    <div
                      className={cn(
                        'flex cursor-pointer items-center justify-between p-2 hover:bg-gray-100 dark:hover:bg-gray-900/80',
                        isExpanded ? 'rounded-t-lg' : 'rounded-lg',
                      )}
                      onClick={() => toggleRawTask(taskId)}
                    >
                      <div className="flex flex-1 flex-col gap-1">
                        <span className="font-mono text-xs font-medium">{taskId}</span>
                        {task?.conversationId && (
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              onCopy(task.conversationId, `${taskId}-conversationId`);
                            }}
                            className="group/copy flex w-fit items-center gap-1 font-mono text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
                          >
                            <span className="max-w-[300px] truncate">
                              Conv: {task.conversationId}
                            </span>
                            {copiedId === `${taskId}-conversationId` ? (
                              <Check className="h-3 w-3 shrink-0 text-green-600" />
                            ) : (
                              <Copy className="h-3 w-3 shrink-0 opacity-0 group-hover/copy:opacity-100" />
                            )}
                          </button>
                        )}
                      </div>
                      <div className="flex items-center gap-1">
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            onCopy(safeStringify(task), taskId);
                          }}
                          className="rounded p-0.5 hover:bg-gray-200 dark:hover:bg-gray-700"
                        >
                          {copiedId === taskId ? (
                            <Check className="h-3 w-3 text-green-600" />
                          ) : (
                            <Copy className="h-3 w-3" />
                          )}
                        </button>
                        {isExpanded ? (
                          <ChevronDown className="h-3 w-3" />
                        ) : (
                          <ChevronRight className="h-3 w-3" />
                        )}
                      </div>
                    </div>
                    <AnimatePresence>
                      {isExpanded && (
                        <motion.div
                          initial={{ height: 0, opacity: 0 }}
                          animate={{ height: 'auto', opacity: 1 }}
                          exit={{ height: 0, opacity: 0 }}
                          transition={{ duration: 0.2 }}
                          className="overflow-hidden"
                        >
                          <div
                            className="rounded-b-lg p-2 pt-0"
                            onClick={(e) => e.stopPropagation()}
                          >
                            <JsonTreeView data={task} onCopy={onCopy} copiedId={copiedId} defaultExpandDepth={2} className="max-h-96" />
                          </div>
                        </motion.div>
                      )}
                    </AnimatePresence>
                  </div>
                );
              })}
            </div>
          )}
        </div>

        {/* Scheduled Executions Section */}
        <div>
          <h3 className="mb-2 text-xs font-semibold text-gray-600 dark:text-gray-400">
            Scheduled Executions ({filteredExecutions.length})
          </h3>
          {filteredExecutions.length === 0 ? (
            <div className="py-4 text-center text-xs text-gray-500">
              {searchQuery ? 'No executions match' : 'No scheduled executions'}
            </div>
          ) : (
            <div className="space-y-2">
              {filteredExecutions.map(([runId, execution]) => {
                const isExpanded = expandedRawExecutions.has(runId);
                return (
                  <div
                    key=[redacted]
                    className="rounded-lg border border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-950"
                  >
                    <div
                      className={cn(
                        'flex cursor-pointer items-center justify-between p-2 hover:bg-gray-100 dark:hover:bg-gray-900/80',
                        isExpanded ? 'rounded-t-lg' : 'rounded-lg',
                      )}
                      onClick={() => toggleRawExecution(runId)}
                    >
                      <div className="flex flex-1 flex-col gap-1">
                        <span className="font-mono text-xs font-medium">{runId}</span>
                        {execution?.threadId && (
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              onCopy(execution.threadId, `${runId}-threadId`);
                            }}
                            className="group/copy flex w-fit items-center gap-1 font-mono text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
                          >
                            <span className="max-w-[300px] truncate">
                              Thread: {execution.threadId}
                            </span>
                            {copiedId === `${runId}-threadId` ? (
                              <Check className="h-3 w-3 shrink-0 text-green-600" />
                            ) : (
                              <Copy className="h-3 w-3 shrink-0 opacity-0 group-hover/copy:opacity-100" />
                            )}
                          </button>
                        )}
                        {execution?.conversationId && (
                          <button
                            onClick={(e) => {
                              e.stopPropagation();
                              onCopy(execution.conversationId, `${runId}-conversationId`);
                            }}
                            className="group/copy flex w-fit items-center gap-1 font-mono text-xs text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
                          >
                            <span className="max-w-[300px] truncate">
                              Conv: {execution.conversationId}
                            </span>
                            {copiedId === `${runId}-conversationId` ? (
                              <Check className="h-3 w-3 shrink-0 text-green-600" />
                            ) : (
                              <Copy className="h-3 w-3 shrink-0 opacity-0 group-hover/copy:opacity-100" />
                            )}
                          </button>
                        )}
                      </div>
                      <div className="flex items-center gap-1">
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            onCopy(safeStringify(execution), runId);
                          }}
                          className="rounded p-0.5 hover:bg-gray-200 dark:hover:bg-gray-700"
                        >
                          {copiedId === runId ? (
                            <Check className="h-3 w-3 text-green-600" />
                          ) : (
                            <Copy className="h-3 w-3" />
                          )}
                        </button>
                        {isExpanded ? (
                          <ChevronDown className="h-3 w-3" />
                        ) : (
                          <ChevronRight className="h-3 w-3" />
                        )}
                      </div>
                    </div>
                    <AnimatePresence>
                      {isExpanded && (
                        <motion.div
                          initial={{ height: 0, opacity: 0 }}
                          animate={{ height: 'auto', opacity: 1 }}
                          exit={{ height: 0, opacity: 0 }}
                          transition={{ duration: 0.2 }}
                          className="overflow-hidden"
                        >
                          <div
                            className="rounded-b-lg p-2 pt-0"
                            onClick={(e) => e.stopPropagation()}
                          >
                            <JsonTreeView data={execution} onCopy={onCopy} copiedId={copiedId} defaultExpandDepth={2} className="max-h-96" />
                          </div>
                        </motion.div>
                      )}
                    </AnimatePresence>
                  </div>
                );
              })}
            </div>
          )}
        </div>
      </div>

      {/* Footer */}
      <div className="border-t border-gray-200 p-2 text-center text-xs text-gray-500 dark:border-gray-700 dark:text-gray-400">
        {searchQuery
          ? `${filteredTasks.length} tasks, ${filteredExecutions.length} executions`
          : `${taskEntries.length} tasks, ${executionEntries.length} scheduled executions`}
      </div>
    </div>
  );
};