Connect the two tools: cross-nav links and Send to Scope Lock handoff
- Add a header link on each tool pointing to the other. - Add a Send to Scope Lock button on Workshop clusters that carry a candidate solution tag. Writes the item to a shared localStorage queue (sde_scope_handoff_v1). - Scope Lock drains that queue on load and adds each item to the Scope Boundary Board as unsorted, deduping by a deterministic id so a repeat send never creates a duplicate. - No backend needed: both tools already share the same browser origin. - Verified with a jsdom test covering send, drain, reload, and re-send-after-reset. - Update README and CHANGELOG.
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
header .brand span{color:#c6c6c6; font-weight:400;}
|
||||
header .spacer{flex:1;}
|
||||
.persist-note{font-size:12px; color:#c6c6c6;}
|
||||
.hdr-btn{background:transparent; color:#fff; border:1px solid #6f6f6f; padding:7px 13px; font-size:13.5px;}
|
||||
.hdr-btn{background:transparent; color:#fff; border:1px solid #6f6f6f; padding:7px 13px; font-size:13.5px; text-decoration:none; display:inline-block;}
|
||||
.hdr-btn:hover{background:#353535;}
|
||||
.hdr-btn.primary{background:var(--interactive); border-color:var(--interactive);}
|
||||
.hdr-btn.primary:hover{background:var(--interactive-hover);}
|
||||
@@ -181,6 +181,7 @@
|
||||
<div class="brand"><strong>Project SDE</strong> <span>| Field Problem Workshop v5</span></div>
|
||||
<div class="spacer"></div>
|
||||
<span class="persist-note">State lives in this session. Save JSON before closing.</span>
|
||||
<a class="hdr-btn" href="/tools/scope-lock-meeting-suite.html">Scope Lock Meeting Suite →</a>
|
||||
<button class="hdr-btn" id="btnLoad">Load JSON</button>
|
||||
<button class="hdr-btn" id="btnSave">Save JSON</button>
|
||||
<button class="hdr-btn" id="btnReset">Reset</button>
|
||||
@@ -388,6 +389,26 @@ function clusterById(id){ return S.clusters.find(c=>c.id===id); }
|
||||
function membersOf(cid){ return S.problems.filter(p=>p.cluster===cid); }
|
||||
function activeMembers(cid){ return S.problems.filter(p=>p.cluster===cid && p.type==='Problem'); }
|
||||
|
||||
/* ================= HANDOFF TO SCOPE LOCK ================= */
|
||||
// Shared localStorage queue that the Scope Lock Meeting Suite reads on load.
|
||||
// Both tools are served from the same origin, so this works with no backend.
|
||||
const SCOPE_HANDOFF_KEY = 'sde_scope_handoff_v1';
|
||||
function sendToScopeLock(c){
|
||||
let queue = [];
|
||||
try{
|
||||
const raw = localStorage.getItem(SCOPE_HANDOFF_KEY);
|
||||
if(raw) queue = JSON.parse(raw);
|
||||
if(!Array.isArray(queue)) queue = [];
|
||||
}catch(e){ queue = []; }
|
||||
queue.push({
|
||||
id: 'ws_' + c.id,
|
||||
t: c.ws,
|
||||
note: c.root || c.name || '',
|
||||
sentAt: Date.now()
|
||||
});
|
||||
try{ localStorage.setItem(SCOPE_HANDOFF_KEY, JSON.stringify(queue)); }catch(e){}
|
||||
}
|
||||
|
||||
document.querySelectorAll('nav button').forEach(b=>{
|
||||
b.addEventListener('click', ()=>{
|
||||
document.querySelectorAll('nav button').forEach(x=>x.classList.remove('active'));
|
||||
@@ -474,6 +495,7 @@ function renderMap(){
|
||||
<span class="cl-count">${mem.length} issue${mem.length===1?'':'s'}${c.ws?' · '+esc(c.ws):''}</span>
|
||||
<span class="spacer"></span>
|
||||
${c.promoted?'<span class="promoted-flag">✓ In Breadcrumbs</span>':`<button class="btn small ghost" data-cprom="${c.id}">Promote →</button>`}
|
||||
${c.ws ? (c.sentToScope ? '<span class="promoted-flag">✓ Sent to Scope Lock</span>' : `<button class="btn small ghost" data-cscope="${c.id}">Send to Scope Lock →</button>`) : ''}
|
||||
<div class="dot-ctl">
|
||||
<button class="dot-btn" data-cdot="${c.id}" data-d="-1">−</button>
|
||||
<span class="dot-n">${c.dots}</span>
|
||||
@@ -508,6 +530,15 @@ document.getElementById('panel-map').addEventListener('click', e=>{
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(t.dataset.cscope){
|
||||
const c = clusterById(t.dataset.cscope);
|
||||
if(c && c.ws && !c.sentToScope){
|
||||
sendToScopeLock(c);
|
||||
c.sentToScope = true;
|
||||
save(); renderMap(); toast('Sent "' + c.ws + '" to Scope Lock');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(t.dataset.cdel){
|
||||
const c = clusterById(t.dataset.cdel);
|
||||
if(c){
|
||||
|
||||
Reference in New Issue
Block a user