feat(phase-b): school/timetable wizards, graph nav panel, UI updates

New components:
- CCGraphNavPanel: Supabase-driven navigation tree (school/timetable/calendar/classes sections),
  role-aware setup buttons, lazy child loading, academic/generic calendar toggle
- SchoolCalendarWizard: 3-step admin-only school setup (details → term dates → daily periods)
- TeacherTimetableWizard: period grid with existing slot pre-loading, edit-mode title

Updated:
- CCNodeSnapshotPanel: saves via Supabase storage path + accessToken
- BasePanel: nav panel tab wired to CCGraphNavPanel
- CCFilesPanelEnhanced: auth context fixes
- CCDocumentIntelligence suite: accessToken threading, Supabase storage integration

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
This commit is contained in:
2026-05-26 01:25:29 +01:00
co-authored by Claude Sonnet 4.6
parent b0c7758135
commit 83adcce951
11 changed files with 1196 additions and 36 deletions
@@ -6,7 +6,7 @@ import { SelectChangeEvent } from '@mui/material/Select';
import { CCDoclingViewer } from './CCDoclingViewer.tsx';
import CCEnhancedFilePanel from './CCEnhancedFilePanel.tsx';
import CCBundleViewer from './CCBundleViewer.tsx';
import { supabase } from '../../../supabaseClient';
import { useAuth } from '../../../contexts/AuthContext';
type CanonicalDoclingConfig = {
pipeline: 'standard' | 'vlm' | 'asr';
@@ -46,6 +46,7 @@ export const CCDocumentIntelligence: React.FC = () => {
const { fileId } = useParams<{ fileId: string }>();
const validFileId = useMemo(() => fileId || '', [fileId]);
const { accessToken } = useAuth();
const [page, setPage] = useState<number>(1);
const [outlineOptions, setOutlineOptions] = useState<Array<{ id: string; title: string; start_page: number; end_page: number }>>([]);
const [profile, setProfile] = useState<Profile>('default');
@@ -148,7 +149,7 @@ export const CCDocumentIntelligence: React.FC = () => {
const loadBundles = async () => {
if (!validFileId) return;
const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
const token = (await supabase.auth.getSession()).data.session?.access_token || '';
const token = accessToken || '';
const res = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, { headers: { Authorization: `Bearer ${token}` } });
if (!res.ok) return;
const arts: Artefact[] = await res.json();
@@ -225,14 +226,14 @@ export const CCDocumentIntelligence: React.FC = () => {
const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
try {
const artsRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts`, {
headers: { 'Authorization': `Bearer ${(await supabase.auth.getSession()).data.session?.access_token || ''}` }
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
});
if (!artsRes.ok) return;
const arts: Array<{ id: string; type: string; rel_path?: string }> = await artsRes.json();
const outlineArt = arts.find(a => a.type === 'document_outline_hierarchy');
if (!outlineArt) return;
const jsonRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts/${encodeURIComponent(outlineArt.id)}/json`, {
headers: { 'Authorization': `Bearer ${(await supabase.auth.getSession()).data.session?.access_token || ''}` }
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
});
if (!jsonRes.ok) return;
const doc = await jsonRes.json();
@@ -242,7 +243,7 @@ export const CCDocumentIntelligence: React.FC = () => {
const splitArt = arts.find(a => a.type === 'split_map_json');
if (splitArt) {
const smRes = await fetch(`${API_BASE}/database/files/${encodeURIComponent(validFileId)}/artefacts/${encodeURIComponent(splitArt.id)}/json`, {
headers: { 'Authorization': `Bearer ${(await supabase.auth.getSession()).data.session?.access_token || ''}` }
headers: { 'Authorization': `Bearer ${accessToken || ''}` }
});
if (smRes.ok) {
const sm = await smRes.json();
@@ -486,7 +487,7 @@ export const CCDocumentIntelligence: React.FC = () => {
try {
setBusy(true);
const API_BASE = import.meta.env.VITE_API_BASE || (location.port.startsWith('517') ? 'http://127.0.0.1:8080' : '/api');
const token = (await supabase.auth.getSession()).data.session?.access_token || '';
const token = accessToken || '';
const body: CanonicalDoclingRequest = {
use_split_map: selectedSectionId === 'full' ? autoSplit : false,
config: {