Isolate SOP/WP data per project (namespaced localStorage)

SOP and Work Package localStorage keys are now namespaced by the active
project via ProjectData.key(base) -> base+'__'+<projectId> (SK() in the
suite, wpKey() in the creator), so switching projects shows that project's
own SOP and packages. project-data.js runs a one-time discard of the legacy
un-namespaced keys (guarded by wp_ns_migrated_v1), per the chosen approach.

Active project is resolved before the store loads in both the suite and the
creator so namespaced keys resolve correctly, including standalone deep-links.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 15:46:59 -07:00
parent 3c40b58ff8
commit e5c450597a
5 changed files with 75 additions and 33 deletions

View File

@@ -758,8 +758,10 @@ function showForm(){ hideDashboard(); document.querySelectorAll('.main > .card')
// ── SAVED PACKAGES ───────────────────────────────────────────────────────────
const STORE_KEY='wp_iwp_v1';
function saveStore(){ try{ localStorage.setItem(STORE_KEY, JSON.stringify(savedPackages)); }catch(e){} }
function loadStore(){ try{ const d=JSON.parse(localStorage.getItem(STORE_KEY)); if(Array.isArray(d)) savedPackages=d; }catch(e){} }
// Per-project namespaced key so each project keeps its own packages in the browser.
function wpKey(base){ try{ return (typeof ProjectData!=='undefined'&&ProjectData.key)?ProjectData.key(base):base; }catch(e){ return base; } }
function saveStore(){ try{ localStorage.setItem(wpKey(STORE_KEY), JSON.stringify(savedPackages)); }catch(e){} }
function loadStore(){ try{ const d=JSON.parse(localStorage.getItem(wpKey(STORE_KEY))); savedPackages=Array.isArray(d)?d:[]; }catch(e){ savedPackages=[]; } }
function renderSavedList(){
const card=document.getElementById('saved-card'), body=document.getElementById('saved-body');
document.getElementById('saved-count').textContent=savedPackages.length?`(${savedPackages.length})`:'';
@@ -1012,15 +1014,23 @@ document.querySelectorAll('#status-group .radio-pill').forEach(p=>p.addEventList
}));
// ── BOOT ─────────────────────────────────────────────────────────────────────
// Resolve the active project BEFORE loading the store so namespaced keys resolve.
(function seedProject(){
const params = new URLSearchParams(location.search);
activeProjectId = params.get('project') || (typeof ProjectData!=='undefined' && ProjectData.getActiveId && ProjectData.getActiveId()) || '';
if(activeProjectId && typeof ProjectData!=='undefined' && ProjectData.getActiveId && ProjectData.getActiveId()!==activeProjectId){
const cached = ProjectData.getActive && ProjectData.getActive();
ProjectData.setActive(cached && cached.id===activeProjectId ? cached : { id: activeProjectId });
}
})();
loadStore();
(function bootSOP(){
// When embedded in the Suite, hide the SOP import/sample controls (SOP is injected)
// and prefer the SOP the Suite just completed (persisted to localStorage).
const params = new URLSearchParams(location.search);
if(params.get('embedded')) document.body.classList.add('embedded');
activeProjectId = params.get('project') || (typeof ProjectData!=='undefined' && ProjectData.getActiveId && ProjectData.getActiveId()) || '';
try {
const raw = localStorage.getItem('wp_suite_sop');
const raw = localStorage.getItem(wpKey('wp_suite_sop'));
if(raw){
const d = JSON.parse(raw);
if(d && d.woTypes){ SOP = d; applySOP(); newPackage(); return; }