updates
This commit is contained in:
parent
97b3486c72
commit
e491e365cd
41
ex4.html
41
ex4.html
|
|
@ -176,7 +176,10 @@
|
|||
}},
|
||||
{ selector: 'edge[label]', style: { 'label': 'data(label)' }},
|
||||
{ selector: 'edge.route', style: { 'line-style': 'dashed','line-color': '#94a3b8','target-arrow-color': '#94a3b8' }},
|
||||
{ selector: 'edge.sg-attach', style: { 'line-style': 'dotted','line-color': '#f59e0b','target-arrow-color': '#f59e0b' }}
|
||||
{ selector: 'edge.sg-attach', style: { 'line-style': 'dotted','line-color': '#f59e0b','target-arrow-color': '#f59e0b' }},
|
||||
{ selector: 'edge.sg-sg', style: { 'line-color': '#f59e0b','target-arrow-color': '#f59e0b','source-arrow-color': '#f59e0b' }},
|
||||
{ selector: 'edge.sg-sg[tarrow > 0]', style: { 'target-arrow-shape': 'triangle' }},
|
||||
{ selector: 'edge.sg-sg[sarrow > 0]', style: { 'source-arrow-shape': 'triangle' }}
|
||||
]
|
||||
});
|
||||
|
||||
|
|
@ -219,6 +222,32 @@
|
|||
const label = `${sg.name || sg.id}\ningress: ${(rin[0]||'—')}${rin.length>1?'…':''}`;
|
||||
elements.push({ data: { id: sg.id, type: 'sg', label, rules: { in: rin, out: rout } } });
|
||||
}
|
||||
// SG<->SG edges based on rules referencing other SGs
|
||||
function parseSgRef(rule){
|
||||
// match: "proto port from sg-xxxx"
|
||||
const m = (rule||'').match(/^(\S+)\s+([^\s]+)\s+from\s+(sg-[0-9a-zA-Z]+)/);
|
||||
if(!m) return null; return { proto:m[1], port:m[2], sg:m[3] };
|
||||
}
|
||||
const pairMap = new Map(); // key: A|B -> {inOn:{}, outFrom:{}}
|
||||
function keyAB(a,b){ return a<b ? (a+'|'+b) : (b+'|'+a); }
|
||||
function ensurePair(a,b){ const k=keyAB(a,b); if(!pairMap.has(k)) pairMap.set(k,{inOn:{},outFrom:{}}); return pairMap.get(k); }
|
||||
function addIn(target, src, proto, port){ const p=ensurePair(target,src); (p.inOn[target]||(p.inOn[target]=[])).push({proto,port,src}); }
|
||||
function addOut(src, target, proto, port){ const p=ensurePair(src,target); (p.outFrom[src]||(p.outFrom[src]=[])).push({proto,port,target}); }
|
||||
for (const sg of sgs) {
|
||||
for (const r of (sg.rules_in||[])) { const x=parseSgRef(r); if(x && sgById[x.sg]) addIn(sg.id, x.sg, x.proto, x.port); }
|
||||
for (const r of (sg.rules_out||[])) { const x=parseSgRef(r); if(x && sgById[x.sg]) addOut(sg.id, x.sg, x.proto, x.port); }
|
||||
}
|
||||
function summarize(list){ const uniq=new Set(); for(const it of (list||[])){ const text=`${it.proto} ${it.port}`; uniq.add(text); } return Array.from(uniq).join(', '); }
|
||||
for (const [k, val] of pairMap.entries()){
|
||||
const [a,b]=k.split('|');
|
||||
const s=a, t=b; // orient stable by id
|
||||
const s2tList = (val.outFrom[s]||[]).concat(val.inOn[t]||[]);
|
||||
const t2sList = (val.outFrom[t]||[]).concat(val.inOn[s]||[]);
|
||||
const tarrow = s2tList.length ? 1 : 0; // arrow at target if flow S->T
|
||||
const sarrow = t2sList.length ? 1 : 0; // arrow at source if flow T->S
|
||||
const label = [summarize(s2tList), summarize(t2sList)].filter(Boolean).join(' | ');
|
||||
elements.push({ data: { id:`sg:${s}|${t}`, source:s, target:t, label, tarrow, sarrow }, classes:'sg-sg' });
|
||||
}
|
||||
// EC2
|
||||
for (const i of ec2s) {
|
||||
const label = `${i.name || i.id}\n${i.id}\n${i.type || ''}\n${i.privateIp ? ('Private IP: ' + i.privateIp) : ''}`;
|
||||
|
|
@ -431,7 +460,7 @@
|
|||
|
||||
document.getElementById('toggle-sg').addEventListener('change',(e)=>{
|
||||
const show=e.target.checked;
|
||||
cy.batch(()=>{ cy.nodes('[type = "sg"]').style('display', show?'element':'none'); cy.edges('.sg-attach').style('display', show?'element':'none'); });
|
||||
cy.batch(()=>{ cy.nodes('[type = "sg"]').style('display', show?'element':'none'); cy.edges('.sg-attach, .sg-sg').style('display', show?'element':'none'); });
|
||||
});
|
||||
document.getElementById('toggle-routes').addEventListener('change',(e)=>{
|
||||
const show=e.target.checked;
|
||||
|
|
@ -470,6 +499,12 @@
|
|||
});
|
||||
cy.fit(undefined,24);
|
||||
}
|
||||
async function tryLoadStartupLayout(){
|
||||
try{
|
||||
const resp = await fetch('layout.json', { cache: 'no-cache' });
|
||||
if(resp && resp.ok){ const data = await resp.json(); applyLayoutData(data); }
|
||||
}catch(e){ /* ignore if missing */ }
|
||||
}
|
||||
document.getElementById('btn-save').addEventListener('click',()=> downloadJSON(snapshotLayout(),'vpc-layout.json'));
|
||||
document.getElementById('btn-load').addEventListener('click',()=> document.getElementById('load-file').click());
|
||||
document.getElementById('load-file').addEventListener('change',(e)=>{
|
||||
|
|
@ -494,6 +529,8 @@
|
|||
const LKEY='vpc-layout-autosave';
|
||||
function saveLocal(){ try{ localStorage.setItem(LKEY, JSON.stringify(snapshotLayout())); }catch{} }
|
||||
function restoreLocal(){ try{ const raw=localStorage.getItem(LKEY); if(raw) applyLayoutData(JSON.parse(raw)); }catch{} }
|
||||
// Load file-based layout first (if present), then restore any local override
|
||||
await tryLoadStartupLayout();
|
||||
restoreLocal();
|
||||
cy.on('position','node', saveLocal);
|
||||
cy.on('mouseup', ()=> { if(labelMode) saveLocal(); });
|
||||
|
|
|
|||
Loading…
Reference in New Issue