Add inline validation feedback for symbol pin row edits
This commit is contained in:
parent
9ee97ffa8e
commit
c02b14649e
@ -74,6 +74,7 @@ const el = {
|
||||
symbolHeightInput: document.getElementById("symbolHeightInput"),
|
||||
addSymbolPinBtn: document.getElementById("addSymbolPinBtn"),
|
||||
applySymbolBtn: document.getElementById("applySymbolBtn"),
|
||||
symbolValidation: document.getElementById("symbolValidation"),
|
||||
symbolPinsList: document.getElementById("symbolPinsList"),
|
||||
pinMeta: document.getElementById("pinMeta"),
|
||||
pinNameInput: document.getElementById("pinNameInput"),
|
||||
@ -880,10 +881,18 @@ function renderSymbolEditorForRef(ref) {
|
||||
el.symbolCategoryInput.value = String(sym.category ?? "");
|
||||
el.symbolWidthInput.value = String(Number(sym.body?.width ?? 120));
|
||||
el.symbolHeightInput.value = String(Number(sym.body?.height ?? 80));
|
||||
el.symbolValidation.textContent = "";
|
||||
el.symbolValidation.classList.remove("symbolValidationError");
|
||||
el.symbolPinsList.innerHTML = (sym.pins ?? []).map((pin) => symbolPinRowHtml(pin)).join("");
|
||||
el.symbolEditor.classList.remove("hidden");
|
||||
}
|
||||
|
||||
function clearSymbolRowValidation(rows) {
|
||||
for (const row of rows) {
|
||||
row.classList.remove("invalidRow");
|
||||
}
|
||||
}
|
||||
|
||||
function renderPinEditor() {
|
||||
if (!state.selectedPin || !state.model) {
|
||||
el.pinEditor.classList.add("hidden");
|
||||
@ -2284,6 +2293,17 @@ function setupEvents() {
|
||||
}
|
||||
});
|
||||
|
||||
el.symbolPinsList.addEventListener("input", (evt) => {
|
||||
const row = evt.target.closest(".symbolPinRow");
|
||||
if (row) {
|
||||
row.classList.remove("invalidRow");
|
||||
}
|
||||
if (el.symbolValidation.textContent) {
|
||||
el.symbolValidation.textContent = "";
|
||||
el.symbolValidation.classList.remove("symbolValidationError");
|
||||
}
|
||||
});
|
||||
|
||||
el.applySymbolBtn.addEventListener("click", () => {
|
||||
if (!state.selectedRef) {
|
||||
return;
|
||||
@ -2302,12 +2322,18 @@ function setupEvents() {
|
||||
}
|
||||
|
||||
const rows = [...el.symbolPinsList.querySelectorAll(".symbolPinRow")];
|
||||
clearSymbolRowValidation(rows);
|
||||
el.symbolValidation.textContent = "";
|
||||
el.symbolValidation.classList.remove("symbolValidationError");
|
||||
if (!rows.length) {
|
||||
el.jsonFeedback.textContent = "Symbol must have at least one pin.";
|
||||
el.symbolValidation.textContent = "Symbol must contain at least one pin row.";
|
||||
el.symbolValidation.classList.add("symbolValidationError");
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedPins = [];
|
||||
const rowErrors = [];
|
||||
for (const row of rows) {
|
||||
const name = String(row.querySelector(".pinName")?.value ?? "").trim();
|
||||
const number = String(row.querySelector(".pinNumber")?.value ?? "").trim();
|
||||
@ -2315,8 +2341,9 @@ function setupEvents() {
|
||||
const offset = Number(row.querySelector(".pinOffset")?.value ?? 0);
|
||||
const type = String(row.querySelector(".pinType")?.value ?? "");
|
||||
if (!name || !number || !PIN_SIDES.includes(side) || !PIN_TYPES.includes(type) || !Number.isFinite(offset) || offset < 0) {
|
||||
el.jsonFeedback.textContent = "Invalid symbol pin row values.";
|
||||
return;
|
||||
row.classList.add("invalidRow");
|
||||
rowErrors.push("Each pin row needs name, number, valid side/type, and offset >= 0.");
|
||||
continue;
|
||||
}
|
||||
parsedPins.push({
|
||||
oldName: row.getAttribute("data-old-pin") ?? name,
|
||||
@ -2324,9 +2351,24 @@ function setupEvents() {
|
||||
});
|
||||
}
|
||||
|
||||
if (rowErrors.length) {
|
||||
el.jsonFeedback.textContent = "Fix invalid symbol pin rows before applying.";
|
||||
el.symbolValidation.textContent = rowErrors[0];
|
||||
el.symbolValidation.classList.add("symbolValidationError");
|
||||
return;
|
||||
}
|
||||
|
||||
const unique = new Set(parsedPins.map((p) => p.pin.name));
|
||||
if (unique.size !== parsedPins.length) {
|
||||
el.jsonFeedback.textContent = "Duplicate pin names are not allowed.";
|
||||
el.symbolValidation.textContent = "Duplicate pin names detected. Each pin name must be unique.";
|
||||
el.symbolValidation.classList.add("symbolValidationError");
|
||||
for (const row of rows) {
|
||||
const name = String(row.querySelector(".pinName")?.value ?? "").trim();
|
||||
if (name && parsedPins.filter((p) => p.pin.name === name).length > 1) {
|
||||
row.classList.add("invalidRow");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2368,6 +2410,8 @@ function setupEvents() {
|
||||
if (state.selectedPin && !pinExists(state.selectedPin.ref, state.selectedPin.pin)) {
|
||||
state.selectedPin = null;
|
||||
}
|
||||
el.symbolValidation.textContent = "";
|
||||
el.symbolValidation.classList.remove("symbolValidationError");
|
||||
const removedPinCount = [...beforePins].filter((p) => !allowedPins.has(p)).length;
|
||||
el.jsonFeedback.textContent = removedPinCount
|
||||
? `Updated symbol ${inst.symbol}. Removed ${removedPinCount} pin mappings from nets/UI metadata.`
|
||||
|
||||
@ -108,6 +108,7 @@
|
||||
<button id="addSymbolPinBtn">Add Pin</button>
|
||||
<button id="applySymbolBtn">Apply Symbol</button>
|
||||
</div>
|
||||
<div id="symbolValidation" class="hintText"></div>
|
||||
<div id="symbolPinsList" class="miniList"></div>
|
||||
</div>
|
||||
<div id="pinEditor" class="editorCard hidden">
|
||||
|
||||
@ -269,6 +269,15 @@ textarea {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.symbolPinRow.invalidRow {
|
||||
background: #fff3f2;
|
||||
}
|
||||
|
||||
.symbolValidationError {
|
||||
color: var(--error);
|
||||
font-size: 0.76rem;
|
||||
}
|
||||
|
||||
.canvasTools {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user