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:
@@ -4,6 +4,10 @@ let currentStep = 1;
|
||||
let sopComplete = false;
|
||||
let allComments = [];
|
||||
|
||||
// Per-project storage key: 'wp_suite_sop' → 'wp_suite_sop__<projId>' when a
|
||||
// project is active. Keeps each project's SOP separate in the browser.
|
||||
function SK(base){ try { return (typeof ProjectData !== 'undefined' && ProjectData.key) ? ProjectData.key(base) : base; } catch(e){ return base; } }
|
||||
|
||||
let state = {
|
||||
project: {name:'', number:'', client:'', division:'', site:''},
|
||||
team: {pm:'', apm:'', cm:'', qm:''},
|
||||
@@ -126,13 +130,15 @@ window.addEventListener('DOMContentLoaded',()=>{
|
||||
renderStandardConstraints();
|
||||
renderSequenceSteps();
|
||||
renderSources();
|
||||
// Resolve the active project FIRST so per-project storage keys are correct
|
||||
// before we restore this project's SOP.
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
applyProjectContext(params.get('project'));
|
||||
restoreSavedSOP();
|
||||
updateStepUI();
|
||||
updateProjectDisplay();
|
||||
|
||||
// Deep-link: ?tab=sop | ?tab=wp | ?view=dashboard | ?project=<id> from the home page.
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
applyProjectContext(params.get('project'));
|
||||
// Deep-link: ?tab=sop | ?tab=wp | ?view=dashboard from the home page.
|
||||
const tab = params.get('tab');
|
||||
if(params.get('view') === 'dashboard') switchTool('wp');
|
||||
else if(tab === 'wp' || tab === 'sop') switchTool(tab);
|
||||
@@ -203,9 +209,9 @@ function loadSampleData(){
|
||||
function restoreSavedSOP(){
|
||||
let savedState = null, savedSop = null, complete = false;
|
||||
try {
|
||||
complete = localStorage.getItem('wp_suite_sop_complete') === '1';
|
||||
savedState = JSON.parse(localStorage.getItem('wp_suite_state') || 'null');
|
||||
savedSop = JSON.parse(localStorage.getItem('wp_suite_sop') || 'null');
|
||||
complete = localStorage.getItem(SK('wp_suite_sop_complete')) === '1';
|
||||
savedState = JSON.parse(localStorage.getItem(SK('wp_suite_state')) || 'null');
|
||||
savedSop = JSON.parse(localStorage.getItem(SK('wp_suite_sop')) || 'null');
|
||||
} catch(e){}
|
||||
if(!complete || !savedState) return;
|
||||
|
||||
@@ -306,15 +312,18 @@ function onSOPReady(){
|
||||
// record so the SOP is authored against the chosen project.
|
||||
let activeProject = null;
|
||||
function applyProjectContext(projectId){
|
||||
try { if(typeof ProjectData !== 'undefined') activeProject = ProjectData.getActive(); } catch(e){}
|
||||
if(projectId && (!activeProject || activeProject.id !== projectId)){
|
||||
// Deep-linked to a project we don't have cached yet — resolve it, then prefill.
|
||||
try {
|
||||
if(typeof ProjectData !== 'undefined'){
|
||||
try {
|
||||
if(typeof ProjectData !== 'undefined'){
|
||||
if(projectId && ProjectData.getActiveId() !== projectId){
|
||||
// Deep-linked to a project that isn't the cached active one. Seed the id
|
||||
// immediately so namespaced storage keys resolve, then fetch the full record.
|
||||
const cached = ProjectData.getActive();
|
||||
ProjectData.setActive(cached && cached.id === projectId ? cached : { id: projectId });
|
||||
ProjectData.get(projectId).then(p => { if(p){ activeProject = p; ProjectData.setActive(p); prefillProjectFields(); updateProjectDisplay(); } });
|
||||
}
|
||||
} catch(e){}
|
||||
}
|
||||
activeProject = ProjectData.getActive();
|
||||
}
|
||||
} catch(e){}
|
||||
prefillProjectFields();
|
||||
}
|
||||
function prefillProjectFields(){
|
||||
@@ -713,11 +722,12 @@ function completeSOP(){
|
||||
sopComplete = true;
|
||||
updateProjectDisplay();
|
||||
|
||||
// Persist for the home page (green / "Review") and for the WP Creator tab.
|
||||
// Persist for the home page (green / "Review") and for the WP Creator tab,
|
||||
// namespaced to the active project so each project keeps its own SOP.
|
||||
try {
|
||||
localStorage.setItem('wp_suite_sop', JSON.stringify(sop));
|
||||
localStorage.setItem('wp_suite_state', JSON.stringify(state));
|
||||
localStorage.setItem('wp_suite_sop_complete', '1');
|
||||
localStorage.setItem(SK('wp_suite_sop'), JSON.stringify(sop));
|
||||
localStorage.setItem(SK('wp_suite_state'), JSON.stringify(state));
|
||||
localStorage.setItem(SK('wp_suite_sop_complete'), '1');
|
||||
} catch(e){}
|
||||
|
||||
track('sop_generated', {woTypes: sop.woTypes.length, constraints: sop.constraints.length});
|
||||
|
||||
Reference in New Issue
Block a user