T7.10 - D5: one analytics implementation, and its report on the admin console
Usage analytics existed as five of the nine colliding globals creator-frame.md counted (ANALYTICS_KEY, analyticsLoad, analyticsSave, downloadAnalytics, showAnalytics), twice - and the wizard's copy had no caller, because the button lived on the creator. The admin console had a THIRD private reader (usageLoad/downloadUsage) that only saw the wizard's key. Now: ONE core, html/wp-usage.js (window.WPUsage: load/save/track/download + the two pre-move storage keys, verbatim). The creator and wizard keep only a thin track() wrapper - page state like the creator's dev-mode pause belongs to the page - and record exactly what they recorded before, under the same keys, so everything captured before this task still reads (probe plants a legacy-format event and finds it in the report). The "Usage data" button left the creator toolbar; the report lives in admin.html's usage card, covering BOTH tools with a download each, behind the same admin gate as the rest of the console (a non-admin sees the denied card and nothing else), usable at 390px. Two probes re-pointed, both with the reason in the code: - cards_check pinned admin.js byte-identical to HEAD - right for T6.5, but as a standing probe it would fail every legitimate later edit; D5 targets admin.js by name. A7's localization is protected by the feature checks and the end-to-end drive, plus a wiring assertion on the block itself. - frame_check listed "Usage data" among the toolbar buttons that must be visible; it now asserts the button is GONE, so the duplicate cannot quietly return. Verification (each probe run alone): NEW tests/usage_check.py 15/15 (grep half: WPUsage defined once, no page touches the keys directly, none of the five globals survives anywhere). Regressions: cards_check ALL PASS, frame_check 39/39. Items: D5 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -3173,14 +3173,11 @@ function openSopModal(){
|
||||
document.getElementById('sop-modal').classList.add('open'); track('view_sop');
|
||||
}
|
||||
function closeSopModal(){ document.getElementById('sop-modal').classList.remove('open'); }
|
||||
const ANALYTICS_KEY='wp_iwp_analytics_v1'; const _session='s_'+Date.now().toString(36)+Math.random().toString(36).slice(2,6);
|
||||
function analyticsLoad(){ try{ return JSON.parse(localStorage.getItem(ANALYTICS_KEY))||{events:[]}; }catch(e){ return {events:[]}; } }
|
||||
function analyticsSave(d){ try{ localStorage.setItem(ANALYTICS_KEY, JSON.stringify(d)); }catch(e){} }
|
||||
function track(event,detail){ if(devMode) return; try{ const d=analyticsLoad(); d.events.push({ts:new Date().toISOString(),session:_session,event,detail:detail||null}); if(d.events.length>5000)d.events=d.events.slice(-5000); analyticsSave(d); }catch(e){} }
|
||||
function showAnalytics(){ const d=analyticsLoad(); const by={}; const ses=new Set(); d.events.forEach(e=>{by[e.event]=(by[e.event]||0)+1;ses.add(e.session);});
|
||||
let t=`USAGE ANALYTICS\n\nSessions: ${ses.size} Events: ${d.events.length}\n\nActions:\n`; Object.keys(by).forEach(k=>t+=` ${k}: ${by[k]}\n`); t+=`\nSaved packages (this device): ${savedPackages.length}\n\nDownload full log as JSON?`;
|
||||
if(confirm(t)) downloadAnalytics(); }
|
||||
function downloadAnalytics(){ const d=analyticsLoad(); const blob=new Blob([JSON.stringify(d,null,2)],{type:'application/json'}); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='wp-iwp-usage-'+new Date().toISOString().slice(0,10)+'.json'; document.body.appendChild(a); a.click(); a.remove(); setTimeout(()=>URL.revokeObjectURL(a.href),1000); track('analytics_exported'); }
|
||||
// D5 / T7.10: the analytics implementation lives in wp-usage.js - ONE copy for
|
||||
// the whole suite - and its report lives on the admin console, where an
|
||||
// operator-facing readout belongs. This page only records. Same key, same
|
||||
// event shape: everything recorded before the move is still readable after it.
|
||||
function track(event,detail){ if(devMode) return; WPUsage.track(WPUsage.KEYS.creator, event, detail); }
|
||||
|
||||
// ── COMMENTS ─────────────────────────────────────────────────────────────────
|
||||
const COMMENTS_KEY='wp_iwp_comments_v1';
|
||||
|
||||
Reference in New Issue
Block a user