Upload folder using huggingface_hub
Browse files
client/src/pages/TutorialTasks.tsx
CHANGED
|
@@ -296,6 +296,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 296 |
const [selectedGroups, setSelectedGroups] = useState<{[key: string]: number}>({});
|
| 297 |
|
| 298 |
const GroupDocSection: React.FC<{ weekNumber: number }> = ({ weekNumber }) => {
|
|
|
|
| 299 |
const [group, setGroup] = useState<number>(() => {
|
| 300 |
const saved = localStorage.getItem(`tutorial_group_${weekNumber}`);
|
| 301 |
return saved ? parseInt(saved) : 1;
|
|
@@ -308,6 +309,7 @@ const TutorialTasks: React.FC = () => {
|
|
| 308 |
const viewMode = (localStorage.getItem('viewMode') || 'auto');
|
| 309 |
const actualRole = (JSON.parse(localStorage.getItem('user') || '{}').role);
|
| 310 |
const isAdmin = viewMode === 'student' ? false : actualRole === 'admin';
|
|
|
|
| 311 |
|
| 312 |
const CopySquaresIcon: React.FC<{ className?: string }> = ({ className }) => (
|
| 313 |
<svg className={className || 'h-4 w-4'} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg">
|
|
@@ -324,11 +326,18 @@ const TutorialTasks: React.FC = () => {
|
|
| 324 |
setTimeout(() => { if (!mutatingTaskId) loadDocs(); }, 400);
|
| 325 |
return;
|
| 326 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 327 |
try { console.log('[Trace] Docs:fetch', { weekNumber }); } catch {}
|
| 328 |
const resp = await api.get(`/api/docs/list?weekNumber=${weekNumber}`);
|
| 329 |
setDocs(resp.data?.docs || []);
|
| 330 |
} catch (e) {
|
| 331 |
setDocs([]);
|
|
|
|
|
|
|
| 332 |
}
|
| 333 |
}, [weekNumber, mutatingTaskId]);
|
| 334 |
|
|
@@ -366,8 +375,25 @@ const TutorialTasks: React.FC = () => {
|
|
| 366 |
} catch {}
|
| 367 |
};
|
| 368 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 369 |
return (
|
| 370 |
-
<div>
|
| 371 |
{/* Top control row */}
|
| 372 |
{isAdmin && (
|
| 373 |
<div className="mb-4 max-w-2xl">
|
|
|
|
| 296 |
const [selectedGroups, setSelectedGroups] = useState<{[key: string]: number}>({});
|
| 297 |
|
| 298 |
const GroupDocSection: React.FC<{ weekNumber: number }> = ({ weekNumber }) => {
|
| 299 |
+
const containerRef = useRef<HTMLDivElement | null>(null);
|
| 300 |
const [group, setGroup] = useState<number>(() => {
|
| 301 |
const saved = localStorage.getItem(`tutorial_group_${weekNumber}`);
|
| 302 |
return saved ? parseInt(saved) : 1;
|
|
|
|
| 309 |
const viewMode = (localStorage.getItem('viewMode') || 'auto');
|
| 310 |
const actualRole = (JSON.parse(localStorage.getItem('user') || '{}').role);
|
| 311 |
const isAdmin = viewMode === 'student' ? false : actualRole === 'admin';
|
| 312 |
+
const isDocsFetchInFlightRef = useRef(false);
|
| 313 |
|
| 314 |
const CopySquaresIcon: React.FC<{ className?: string }> = ({ className }) => (
|
| 315 |
<svg className={className || 'h-4 w-4'} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" xmlns="http://www.w3.org/2000/svg">
|
|
|
|
| 326 |
setTimeout(() => { if (!mutatingTaskId) loadDocs(); }, 400);
|
| 327 |
return;
|
| 328 |
}
|
| 329 |
+
if (isDocsFetchInFlightRef.current) {
|
| 330 |
+
try { console.log('[Trace] Docs:skipInFlight', { weekNumber }); } catch {}
|
| 331 |
+
return;
|
| 332 |
+
}
|
| 333 |
+
isDocsFetchInFlightRef.current = true;
|
| 334 |
try { console.log('[Trace] Docs:fetch', { weekNumber }); } catch {}
|
| 335 |
const resp = await api.get(`/api/docs/list?weekNumber=${weekNumber}`);
|
| 336 |
setDocs(resp.data?.docs || []);
|
| 337 |
} catch (e) {
|
| 338 |
setDocs([]);
|
| 339 |
+
} finally {
|
| 340 |
+
isDocsFetchInFlightRef.current = false;
|
| 341 |
}
|
| 342 |
}, [weekNumber, mutatingTaskId]);
|
| 343 |
|
|
|
|
| 375 |
} catch {}
|
| 376 |
};
|
| 377 |
|
| 378 |
+
useEffect(() => {
|
| 379 |
+
const el = containerRef.current;
|
| 380 |
+
if (!el) return;
|
| 381 |
+
if (mutatingTaskId) {
|
| 382 |
+
const h = el.getBoundingClientRect().height;
|
| 383 |
+
try { console.log('[Trace] Docs:lockHeight', { h }); } catch {}
|
| 384 |
+
el.style.minHeight = `${h}px`;
|
| 385 |
+
el.style.height = `${h}px`;
|
| 386 |
+
el.style.overflow = 'hidden';
|
| 387 |
+
} else {
|
| 388 |
+
el.style.minHeight = '';
|
| 389 |
+
el.style.height = '';
|
| 390 |
+
el.style.overflow = '';
|
| 391 |
+
try { console.log('[Trace] Docs:unlockHeight'); } catch {}
|
| 392 |
+
}
|
| 393 |
+
}, [mutatingTaskId]);
|
| 394 |
+
|
| 395 |
return (
|
| 396 |
+
<div ref={containerRef}>
|
| 397 |
{/* Top control row */}
|
| 398 |
{isAdmin && (
|
| 399 |
<div className="mb-4 max-w-2xl">
|