Add destructive-action confirmations in inspector editors
This commit is contained in:
parent
fcad4b284b
commit
31d2182258
@ -1701,6 +1701,51 @@ function hasNodeOnNet(net, ref, pin) {
|
||||
return (net.nodes ?? []).some((n) => n.ref === ref && n.pin === pin);
|
||||
}
|
||||
|
||||
function refsForSymbol(symbolId) {
|
||||
return new Set((state.model?.instances ?? []).filter((i) => i.symbol === symbolId).map((i) => i.ref));
|
||||
}
|
||||
|
||||
function symbolPinUsage(symbolId, pinName) {
|
||||
const refs = refsForSymbol(symbolId);
|
||||
const nets = new Set();
|
||||
let nodes = 0;
|
||||
for (const net of state.model?.nets ?? []) {
|
||||
for (const node of net.nodes ?? []) {
|
||||
if (refs.has(node.ref) && node.pin === pinName) {
|
||||
nodes += 1;
|
||||
nets.add(net.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return { refs: refs.size, nodes, nets: [...nets].sort() };
|
||||
}
|
||||
|
||||
function disconnectImpact(netName, ref, pin) {
|
||||
const net = netByName(netName);
|
||||
if (!net) {
|
||||
return { remainingNodes: 0, orphaned: false };
|
||||
}
|
||||
const remainingNodes = (net.nodes ?? []).filter((n) => !(n.ref === ref && n.pin === pin)).length;
|
||||
return {
|
||||
remainingNodes,
|
||||
orphaned: remainingNodes < 2
|
||||
};
|
||||
}
|
||||
|
||||
function deleteComponentImpact(ref) {
|
||||
const impacted = [];
|
||||
let removedNodes = 0;
|
||||
for (const net of state.model?.nets ?? []) {
|
||||
const before = net.nodes?.length ?? 0;
|
||||
const after = (net.nodes ?? []).filter((n) => n.ref !== ref).length;
|
||||
if (before !== after) {
|
||||
removedNodes += before - after;
|
||||
impacted.push({ name: net.name, removed: before - after, orphaned: after < 2 });
|
||||
}
|
||||
}
|
||||
return { removedNodes, impacted };
|
||||
}
|
||||
|
||||
function connectPinToNet(ref, pin, netName, opts = {}) {
|
||||
if (!state.model) {
|
||||
return { ok: false, message: "No model loaded." };
|
||||
@ -2283,6 +2328,16 @@ function setupEvents() {
|
||||
return;
|
||||
}
|
||||
const ref = state.selectedRef;
|
||||
const impact = deleteComponentImpact(ref);
|
||||
const orphaned = impact.impacted.filter((x) => x.orphaned).map((x) => x.name);
|
||||
const summary =
|
||||
`Delete ${ref}?\n` +
|
||||
`- Net nodes removed: ${impact.removedNodes}\n` +
|
||||
`- Nets touched: ${impact.impacted.length}\n` +
|
||||
(orphaned.length ? `- Nets that will be removed (<2 nodes): ${orphaned.slice(0, 8).join(", ")}${orphaned.length > 8 ? " ..." : ""}\n` : "");
|
||||
if (!window.confirm(summary)) {
|
||||
return;
|
||||
}
|
||||
pushHistory("delete-component");
|
||||
state.model.instances = state.model.instances.filter((i) => i.ref !== ref);
|
||||
for (const net of state.model.nets ?? []) {
|
||||
@ -2416,6 +2471,13 @@ function setupEvents() {
|
||||
return;
|
||||
}
|
||||
const netName = btn.getAttribute("data-disconnect-net");
|
||||
const impact = disconnectImpact(netName, state.selectedPin.ref, state.selectedPin.pin);
|
||||
const message = impact.orphaned
|
||||
? `Disconnect ${state.selectedPin.ref}.${state.selectedPin.pin} from ${netName}?\nThis will leave fewer than 2 nodes and remove net '${netName}'.`
|
||||
: `Disconnect ${state.selectedPin.ref}.${state.selectedPin.pin} from ${netName}?`;
|
||||
if (!window.confirm(message)) {
|
||||
return;
|
||||
}
|
||||
pushHistory("disconnect-pin");
|
||||
const out = disconnectPinFromNet(state.selectedPin.ref, state.selectedPin.pin, netName);
|
||||
if (!out.ok) {
|
||||
@ -2487,6 +2549,13 @@ function setupEvents() {
|
||||
const netName = state.selectedNet;
|
||||
const [ref, ...pinParts] = String(btn.getAttribute("data-remove-node")).split(".");
|
||||
const pin = pinParts.join(".");
|
||||
const impact = disconnectImpact(netName, ref, pin);
|
||||
const message = impact.orphaned
|
||||
? `Remove ${ref}.${pin} from ${netName}?\nThis will leave fewer than 2 nodes and remove net '${netName}'.`
|
||||
: `Remove ${ref}.${pin} from ${netName}?`;
|
||||
if (!window.confirm(message)) {
|
||||
return;
|
||||
}
|
||||
pushHistory("net-node-remove");
|
||||
const out = disconnectPinFromNet(ref, pin, netName);
|
||||
if (!out.ok) {
|
||||
@ -2532,6 +2601,22 @@ function setupEvents() {
|
||||
}
|
||||
const row = btn.closest(".symbolPinRow");
|
||||
if (row) {
|
||||
const pinName = String(row.querySelector(".pinName")?.value ?? row.getAttribute("data-old-pin") ?? "").trim();
|
||||
const inst = state.selectedRef ? instanceByRef(state.selectedRef) : null;
|
||||
if (inst && pinName) {
|
||||
const usage = symbolPinUsage(inst.symbol, pinName);
|
||||
if (usage.nodes > 0) {
|
||||
const netSample = usage.nets.slice(0, 8).join(", ");
|
||||
const suffix = usage.nets.length > 8 ? " ..." : "";
|
||||
const prompt =
|
||||
`Remove pin row '${pinName}' from symbol '${inst.symbol}' editor?\n` +
|
||||
`Current usage: ${usage.nodes} net node(s) across ${usage.nets.length} net(s): ${netSample}${suffix}\n` +
|
||||
"These references will be dropped when you apply symbol changes.";
|
||||
if (!window.confirm(prompt)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
row.remove();
|
||||
invalidateSymbolMigrationPreview("Pin rows changed. Preview migration again before apply.");
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user