Spaces:
Sleeping
Sleeping
Upload static/js/data_manager.js with huggingface_hub
Browse files- static/js/data_manager.js +215 -0
static/js/data_manager.js
ADDED
@@ -0,0 +1,215 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/**
|
2 |
+
* Data Manager Module
|
3 |
+
* Handles caching and retrieval of trade data to reduce API calls
|
4 |
+
*/
|
5 |
+
|
6 |
+
const DataManager = (function() {
|
7 |
+
// In-memory cache
|
8 |
+
const memoryCache = {};
|
9 |
+
|
10 |
+
// Check if localStorage is available
|
11 |
+
const storageAvailable = function() {
|
12 |
+
try {
|
13 |
+
const storage = window.localStorage;
|
14 |
+
const x = '__storage_test__';
|
15 |
+
storage.setItem(x, x);
|
16 |
+
storage.removeItem(x);
|
17 |
+
return true;
|
18 |
+
} catch(e) {
|
19 |
+
return false;
|
20 |
+
}
|
21 |
+
};
|
22 |
+
|
23 |
+
// Generate a cache key from request parameters
|
24 |
+
const generateCacheKey = function(params) {
|
25 |
+
return `trade_data_${params.reporterCode}_${params.partnerCode}_${params.period}_${params.cmdCode}_${params.flowCode || 'all'}`;
|
26 |
+
};
|
27 |
+
|
28 |
+
// Save data to localStorage and memory cache
|
29 |
+
const saveToCache = function(params, data) {
|
30 |
+
const key = generateCacheKey(params);
|
31 |
+
|
32 |
+
// Save to memory cache
|
33 |
+
memoryCache[key] = {
|
34 |
+
timestamp: Date.now(),
|
35 |
+
data: data
|
36 |
+
};
|
37 |
+
|
38 |
+
// Save to localStorage if available
|
39 |
+
if (storageAvailable()) {
|
40 |
+
try {
|
41 |
+
localStorage.setItem(key, JSON.stringify({
|
42 |
+
timestamp: Date.now(),
|
43 |
+
data: data
|
44 |
+
}));
|
45 |
+
} catch(e) {
|
46 |
+
console.warn('Failed to save to localStorage:', e);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
};
|
50 |
+
|
51 |
+
// Get data from cache
|
52 |
+
const getFromCache = function(params) {
|
53 |
+
const key = generateCacheKey(params);
|
54 |
+
|
55 |
+
// Try memory cache first
|
56 |
+
if (memoryCache[key]) {
|
57 |
+
return memoryCache[key].data;
|
58 |
+
}
|
59 |
+
|
60 |
+
// Try localStorage
|
61 |
+
if (storageAvailable()) {
|
62 |
+
try {
|
63 |
+
const storedData = localStorage.getItem(key);
|
64 |
+
if (storedData) {
|
65 |
+
const parsed = JSON.parse(storedData);
|
66 |
+
// Refresh memory cache with this data
|
67 |
+
memoryCache[key] = parsed;
|
68 |
+
return parsed.data;
|
69 |
+
}
|
70 |
+
} catch(e) {
|
71 |
+
console.warn('Failed to retrieve from localStorage:', e);
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
return null;
|
76 |
+
};
|
77 |
+
|
78 |
+
// Check if data is cached
|
79 |
+
const isDataCached = function(params) {
|
80 |
+
return getFromCache(params) !== null;
|
81 |
+
};
|
82 |
+
|
83 |
+
// Export CSV from data
|
84 |
+
const exportToCsv = function(data, filename = 'trade_data.csv') {
|
85 |
+
if (!data || !data.columns || !data.rows || data.rows.length === 0) {
|
86 |
+
console.error('Invalid data for CSV export');
|
87 |
+
return false;
|
88 |
+
}
|
89 |
+
|
90 |
+
// Create CSV header row
|
91 |
+
let csv = data.columns.join(',') + '\n';
|
92 |
+
|
93 |
+
// Add data rows
|
94 |
+
data.rows.forEach(row => {
|
95 |
+
const rowValues = data.columns.map(col => {
|
96 |
+
// Handle value that might contain commas
|
97 |
+
const value = row[col] !== undefined ? row[col] : '';
|
98 |
+
if (typeof value === 'string' && (value.includes(',') || value.includes('"') || value.includes('\n'))) {
|
99 |
+
return `"${value.replace(/"/g, '""')}"`;
|
100 |
+
}
|
101 |
+
return value;
|
102 |
+
});
|
103 |
+
csv += rowValues.join(',') + '\n';
|
104 |
+
});
|
105 |
+
|
106 |
+
// Create and trigger download
|
107 |
+
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
|
108 |
+
const url = URL.createObjectURL(blob);
|
109 |
+
|
110 |
+
const link = document.createElement('a');
|
111 |
+
link.setAttribute('href', url);
|
112 |
+
link.setAttribute('download', filename);
|
113 |
+
link.style.visibility = 'hidden';
|
114 |
+
document.body.appendChild(link);
|
115 |
+
link.click();
|
116 |
+
document.body.removeChild(link);
|
117 |
+
|
118 |
+
return true;
|
119 |
+
};
|
120 |
+
|
121 |
+
// List all cached data sets
|
122 |
+
const listCachedData = function() {
|
123 |
+
const cachedData = [];
|
124 |
+
|
125 |
+
// List from memory cache
|
126 |
+
for (const key in memoryCache) {
|
127 |
+
if (key.startsWith('trade_data_')) {
|
128 |
+
const parts = key.split('_');
|
129 |
+
cachedData.push({
|
130 |
+
key: key,
|
131 |
+
reporter: parts[2],
|
132 |
+
partner: parts[3],
|
133 |
+
year: parts[4],
|
134 |
+
commodity: parts[5],
|
135 |
+
flow: parts[6],
|
136 |
+
timestamp: new Date(memoryCache[key].timestamp).toLocaleString()
|
137 |
+
});
|
138 |
+
}
|
139 |
+
}
|
140 |
+
|
141 |
+
// Combine with any localStorage data not in memory
|
142 |
+
if (storageAvailable()) {
|
143 |
+
for (let i = 0; i < localStorage.length; i++) {
|
144 |
+
const key = localStorage.key(i);
|
145 |
+
if (key.startsWith('trade_data_') && !memoryCache[key]) {
|
146 |
+
try {
|
147 |
+
const data = JSON.parse(localStorage.getItem(key));
|
148 |
+
const parts = key.split('_');
|
149 |
+
cachedData.push({
|
150 |
+
key: key,
|
151 |
+
reporter: parts[2],
|
152 |
+
partner: parts[3],
|
153 |
+
year: parts[4],
|
154 |
+
commodity: parts[5],
|
155 |
+
flow: parts[6],
|
156 |
+
timestamp: new Date(data.timestamp).toLocaleString()
|
157 |
+
});
|
158 |
+
} catch(e) {
|
159 |
+
console.warn('Failed to parse localStorage item:', key);
|
160 |
+
}
|
161 |
+
}
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
return cachedData;
|
166 |
+
};
|
167 |
+
|
168 |
+
// Clear specific cache entry
|
169 |
+
const clearCacheEntry = function(key) {
|
170 |
+
// Clear from memory
|
171 |
+
if (memoryCache[key]) {
|
172 |
+
delete memoryCache[key];
|
173 |
+
}
|
174 |
+
|
175 |
+
// Clear from localStorage
|
176 |
+
if (storageAvailable()) {
|
177 |
+
localStorage.removeItem(key);
|
178 |
+
}
|
179 |
+
};
|
180 |
+
|
181 |
+
// Clear all cache
|
182 |
+
const clearAllCache = function() {
|
183 |
+
// Clear memory cache
|
184 |
+
for (const key in memoryCache) {
|
185 |
+
if (key.startsWith('trade_data_')) {
|
186 |
+
delete memoryCache[key];
|
187 |
+
}
|
188 |
+
}
|
189 |
+
|
190 |
+
// Clear localStorage
|
191 |
+
if (storageAvailable()) {
|
192 |
+
const keysToRemove = [];
|
193 |
+
for (let i = 0; i < localStorage.length; i++) {
|
194 |
+
const key = localStorage.key(i);
|
195 |
+
if (key.startsWith('trade_data_')) {
|
196 |
+
keysToRemove.push(key);
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
// Remove items separately to avoid index issues
|
201 |
+
keysToRemove.forEach(key => localStorage.removeItem(key));
|
202 |
+
}
|
203 |
+
};
|
204 |
+
|
205 |
+
// Public API
|
206 |
+
return {
|
207 |
+
saveToCache,
|
208 |
+
getFromCache,
|
209 |
+
isDataCached,
|
210 |
+
exportToCsv,
|
211 |
+
listCachedData,
|
212 |
+
clearCacheEntry,
|
213 |
+
clearAllCache
|
214 |
+
};
|
215 |
+
})();
|