File size: 3,928 Bytes
d3ad7d5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import { useEffect, useState } from 'react';
import { Database, HardDrive, RefreshCw, Download } from 'lucide-react';
import './CachePanel.css';

interface Dataset {
    variable: string;
    query_type: string;
    start_date: string;
    end_date: string;
    lat_bounds: [number, number];
    lon_bounds: [number, number];
    file_size_bytes: number;
    path: string;
}

interface CacheData {
    datasets: Dataset[];
    total_size_bytes: number;
}

function formatBytes(bytes: number): string {
    if (bytes < 1024) return bytes + ' B';
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
    if (bytes < 1024 * 1024 * 1024) return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
    return (bytes / (1024 * 1024 * 1024)).toFixed(2) + ' GB';
}

async function downloadDataset(path: string) {
    try {
        const resp = await fetch(`/api/cache/download?path=${encodeURIComponent(path)}`);
        if (!resp.ok) throw new Error('Download failed');
        const blob = await resp.blob();
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = path.split('/').pop() + '.zip';
        document.body.appendChild(a);
        a.click();
        a.remove();
        URL.revokeObjectURL(url);
    } catch (err) {
        console.error('Download error:', err);
    }
}

export default function CachePanel() {
    const [cache, setCache] = useState<CacheData | null>(null);
    const [loading, setLoading] = useState(false);

    const fetchCache = async () => {
        setLoading(true);
        try {
            const res = await fetch('/api/cache');
            if (res.ok) setCache(await res.json());
        } catch { /* ignore */ }
        setLoading(false);
    };

    useEffect(() => { fetchCache(); }, []);

    return (
        <div className="cache-panel">
            <div className="cache-header">
                <div className="cache-title">
                    <Database size={16} />
                    <span>Cached Datasets</span>
                </div>
                <button className="cache-refresh" onClick={fetchCache} disabled={loading} title="Refresh">
                    <RefreshCw size={14} className={loading ? 'spin' : ''} />
                </button>
            </div>

            {cache && cache.datasets.length > 0 ? (
                <>
                    <div className="cache-summary">
                        <HardDrive size={13} />
                        <span>{cache.datasets.length} datasets · {formatBytes(cache.total_size_bytes)}</span>
                    </div>
                    <ul className="cache-list">
                        {cache.datasets.map((ds, i) => (
                            <li key={i} className="cache-item">
                                <div className="cache-item-row">
                                    <div>
                                        <div className="cache-var">{ds.variable}</div>
                                        <div className="cache-meta">
                                            {ds.start_date} → {ds.end_date} · {formatBytes(ds.file_size_bytes)}
                                        </div>
                                    </div>
                                    <button
                                        className="cache-dl-btn"
                                        onClick={() => downloadDataset(ds.path)}
                                        title="Download as ZIP"
                                    >
                                        <Download size={13} />
                                    </button>
                                </div>
                            </li>
                        ))}
                    </ul>
                </>
            ) : (
                <div className="cache-empty">No cached datasets yet</div>
            )}
        </div>
    );
}