feat: add live inspector button, deep API detail logging, and diagnostic report download
This commit is contained in:
@@ -35,6 +35,9 @@
|
|||||||
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
|
<button id="inspectFeedBtn" class="secondary-btn" style="padding: 4px 10px; font-size: 11.5px; margin-left: 8px;">
|
||||||
|
🔬 Inspect Live Tab
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|||||||
@@ -263,6 +263,10 @@ function setupEventListeners() {
|
|||||||
checkSessionAndDiscoverStudents();
|
checkSessionAndDiscoverStudents();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (el.inspectFeedBtn) {
|
||||||
|
el.inspectFeedBtn.addEventListener('click', handleInspectFeed);
|
||||||
|
}
|
||||||
|
|
||||||
el.setManualIdBtn.addEventListener('click', () => {
|
el.setManualIdBtn.addEventListener('click', () => {
|
||||||
const customId = el.manualStudentId.value.trim();
|
const customId = el.manualStudentId.value.trim();
|
||||||
if (!customId) return;
|
if (!customId) return;
|
||||||
@@ -308,6 +312,69 @@ function setupEventListeners() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleInspectFeed() {
|
||||||
|
log('🔬 Inspecting live Brightwheel tab...', 'info');
|
||||||
|
try {
|
||||||
|
const [bwTab] = await chrome.tabs.query({ url: 'https://schools.mybrightwheel.com/*' });
|
||||||
|
if (!bwTab || !bwTab.id) {
|
||||||
|
log('No active Brightwheel tab found at schools.mybrightwheel.com. Please ensure the feed is open in a tab.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chrome.tabs.sendMessage(bwTab.id, {
|
||||||
|
action: 'INSPECT_LIVE_FEED',
|
||||||
|
studentId: state.selectedStudentId
|
||||||
|
}, (res) => {
|
||||||
|
if (!res || !res.success) {
|
||||||
|
log('Inspection response error: ' + (res?.error || 'Could not communicate with tab. Try refreshing the Brightwheel tab.'), 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(`✅ Live Inspection Complete for: ${res.currentUrl}`, 'success');
|
||||||
|
log(`Page Title: "${res.pageTitle}"`, 'info');
|
||||||
|
log(`DOM Cards Detected on Page: ${res.domCards?.length || 0}`, 'info');
|
||||||
|
|
||||||
|
if (res.domCards && res.domCards.length > 0) {
|
||||||
|
res.domCards.slice(0, 3).forEach((dc, i) => {
|
||||||
|
log(` [DOM Card ${i + 1}] Text: "${dc.raw_text.replace(/\s+/g, ' ').substring(0, 100)}..."`, 'info');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const acts = res.apiSampleActivities || [];
|
||||||
|
log(`API Sample Activities Received: ${acts.length}`, 'success');
|
||||||
|
|
||||||
|
acts.forEach((a, idx) => {
|
||||||
|
const type = a.activity_type || a.action_type || a.type;
|
||||||
|
const presentKeys = Object.keys(a).filter(k => a[k] !== null && a[k] !== undefined && a[k] !== '');
|
||||||
|
log(`[API Item ${idx + 1}] Type="${type}", Note="${a.note || a.body || ''}", Keys=[${presentKeys.join(', ')}]`, 'info');
|
||||||
|
|
||||||
|
if (type === 'ac_video' || type === 'video') {
|
||||||
|
log(` -> Video payload: media=${JSON.stringify(a.media || null)}, video_url=${a.video_url || null}`, 'warn');
|
||||||
|
}
|
||||||
|
if (type === 'ac_nap' || type === 'nap') {
|
||||||
|
log(` -> Nap payload: action_type=${a.action_type}, nap_start=${a.nap_start || a.start_time}, nap_end=${a.nap_end || a.end_time}, duration=${a.duration || a.duration_minutes}`, 'warn');
|
||||||
|
}
|
||||||
|
if (type === 'ac_checkin' || type === 'checkin') {
|
||||||
|
log(` -> Checkin payload: action_type=${a.action_type}, signed_in_by=${a.signed_in_by || a.actor_name || a.guardian_name}, event_type=${a.event_type}`, 'warn');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Automatically download inspection JSON report
|
||||||
|
const blob = new Blob([JSON.stringify(res, null, 2)], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = `brightwheel_inspection_${state.selectedStudentId}_${Date.now()}.json`;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
log(`📁 Downloaded full inspection report to your Downloads folder (${(blob.size/1024).toFixed(1)} KB).`, 'success');
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
log('Inspection error: ' + e.message, 'error');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
// Main Export Process Engine
|
// Main Export Process Engine
|
||||||
// -------------------------------------------------------------
|
// -------------------------------------------------------------
|
||||||
|
|||||||
+35
-27
@@ -40,39 +40,47 @@
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.action === 'SCRAPE_DOM_FEED') {
|
if (message.action === 'INSPECT_LIVE_FEED') {
|
||||||
|
(async () => {
|
||||||
try {
|
try {
|
||||||
const domActivities = scrapeDomFeedCards();
|
const studentId = message.studentId || detectCurrentStudentId();
|
||||||
sendResponse({ success: true, activities: domActivities, htmlSample: document.body.innerHTML.substring(0, 5000) });
|
const apiListRes = await fetch(`https://schools.mybrightwheel.com/api/v1/students/${studentId}/activities?page_size=25`, {
|
||||||
|
credentials: 'include',
|
||||||
|
headers: { 'Accept': 'application/json' }
|
||||||
|
}).then(r => r.json()).catch(e => ({ error: e.message }));
|
||||||
|
|
||||||
|
const rawActs = apiListRes?.activities || apiListRes?.items || [];
|
||||||
|
|
||||||
|
// Sample detail fetches for video, nap, checkin
|
||||||
|
const sampleDetails = {};
|
||||||
|
for (const act of rawActs.slice(0, 10)) {
|
||||||
|
const type = act.activity_type || act.action_type || act.type;
|
||||||
|
if (!sampleDetails[type] && act.id) {
|
||||||
|
const detail = await fetch(`https://schools.mybrightwheel.com/api/v1/students/${studentId}/activities/${act.id}`, {
|
||||||
|
credentials: 'include',
|
||||||
|
headers: { 'Accept': 'application/json' }
|
||||||
|
}).then(r => r.json()).catch(e => ({ error: e.message }));
|
||||||
|
sampleDetails[type] = detail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const domCards = scrapeDomFeedCards();
|
||||||
|
|
||||||
|
sendResponse({
|
||||||
|
success: true,
|
||||||
|
studentId,
|
||||||
|
apiSampleActivities: rawActs.slice(0, 10),
|
||||||
|
sampleDetails,
|
||||||
|
domCards: domCards.slice(0, 20),
|
||||||
|
pageTitle: document.title,
|
||||||
|
currentUrl: window.location.href
|
||||||
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
sendResponse({ success: false, error: err.message });
|
sendResponse({ success: false, error: err.message });
|
||||||
}
|
}
|
||||||
return true;
|
})();
|
||||||
}
|
|
||||||
|
|
||||||
if (message.action === 'FETCH_WITH_CREDENTIALS') {
|
|
||||||
fetch(message.url, {
|
|
||||||
method: message.method || 'GET',
|
|
||||||
headers: {
|
|
||||||
'Accept': 'application/json',
|
|
||||||
...(message.headers || {})
|
|
||||||
},
|
|
||||||
credentials: 'include'
|
|
||||||
})
|
|
||||||
.then(async (res) => {
|
|
||||||
if (!res.ok) {
|
|
||||||
const errorText = await res.text().catch(() => '');
|
|
||||||
return sendResponse({ success: false, status: res.status, statusText: res.statusText, body: errorText });
|
|
||||||
}
|
|
||||||
const json = await res.json();
|
|
||||||
sendResponse({ success: true, status: res.status, data: json });
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
sendResponse({ success: false, error: err.message });
|
|
||||||
});
|
|
||||||
return true; // async
|
return true; // async
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// DOM Scraper for Brightwheel Web Feed
|
// DOM Scraper for Brightwheel Web Feed
|
||||||
function scrapeDomFeedCards() {
|
function scrapeDomFeedCards() {
|
||||||
|
|||||||
Reference in New Issue
Block a user