File size: 3,732 Bytes
51089d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8b1baa1
51089d0
8b1baa1
 
51089d0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import { useCallback, useEffect, useMemo, useState } from 'react';
import { LuImageOff, LuLoader, LuBan } from 'react-icons/lu';
import DatasetImageCard from './DatasetImageCard';
import classNames from 'classnames';
import { apiClient } from '@/utils/api';

type LoadState = 'idle' | 'loading' | 'success' | 'error' | 'empty';

interface DatasetPreviewGridProps {
  datasetName?: string | null;
  refreshKey?: number;
  className?: string;
  emptyMessage?: string;
  compact?: boolean;
}

export default function DatasetPreviewGrid({
  datasetName,
  refreshKey = 0,
  className = '',
  emptyMessage = 'No files uploaded yet. Add images or videos to see them here.',
  compact = false,
}: DatasetPreviewGridProps) {
  const [status, setStatus] = useState<LoadState>('idle');
  const [items, setItems] = useState<{ img_path: string }[]>([]);

  const fetchMedia = useCallback(async () => {
    const trimmedName = datasetName?.trim();
    if (!trimmedName) {
      setItems([]);
      setStatus('idle');
      return;
    }

    setStatus('loading');
    try {
      const response = await apiClient
        .post('/api/datasets/listImages', { datasetName: trimmedName })
        .then(res => res.data);

      const sorted = Array.isArray(response?.images)
        ? [...response.images].sort((a, b) => a.img_path.localeCompare(b.img_path))
        : [];

      setItems(sorted);
      setStatus(sorted.length === 0 ? 'empty' : 'success');
    } catch (error) {
      console.error('Failed to fetch dataset preview:', error);
      setItems([]);
      setStatus('error');
    }
  }, [datasetName]);

  useEffect(() => {
    fetchMedia();
  }, [fetchMedia, refreshKey]);

  const content = useMemo(() => {
    switch (status) {
      case 'idle':
        return (
          <div className="text-sm text-gray-500 bg-gray-900/60 border border-gray-800 rounded-md px-4 py-6 text-center">
            Select or upload a dataset to preview its contents.
          </div>
        );
      case 'loading':
        return (
          <div className="flex flex-col items-center justify-center gap-3 py-8 text-sm text-gray-300">
            <LuLoader className="animate-spin w-6 h-6" />
            <span>Loading dataset contents…</span>
          </div>
        );
      case 'error':
        return (
          <div className="flex flex-col items-center justify-center gap-3 py-8 text-sm text-red-300 bg-red-950/30 border border-red-800 rounded-md">
            <LuBan className="w-6 h-6" />
            <span>Unable to load dataset media. Verify the dataset exists and try again.</span>
          </div>
        );
      case 'empty':
        return (
          <div className="flex flex-col items-center justify-center gap-3 py-8 text-sm text-gray-400 bg-gray-900/60 border border-dashed border-gray-700 rounded-md">
            <LuImageOff className="w-6 h-6" />
            <span>{emptyMessage}</span>
          </div>
        );
      case 'success':
        return (
          <div
            className={classNames(
              'grid gap-3 sm:gap-4',
              compact
                ? 'grid-cols-2 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5'
                : 'grid-cols-2 sm:grid-cols-3 md:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6',
            )}
          >
            {items.map(item => (
              <DatasetImageCard
                key={item.img_path}
                imageUrl={item.img_path}
                alt="Dataset media"
                onDelete={fetchMedia}
              />
            ))}
          </div>
        );
      default:
        return null;
    }
  }, [status, items, emptyMessage, compact, fetchMedia]);

  return <div className={classNames('space-y-4', className)}>{content}</div>;
}