holder: cap total cells at 1000 to prevent runaway renders

User-triggered 120x120 = 14400 cells, which produces huge STL/long
renders. Total cells is the right metric (CSG cost scales with count,
not max axis), so cap by N = rows*cols (or rows*(rows+1)/2 for tria
style). 1000 covers any realistic pack (e.g. 20x50) while blocking
accidental misuse.

Backend:
- holder.py: MAX_CELLS env-tunable (default 1000); expected_cell_count
  and _check_cell_limit raise ValueError on exceed; both
  compute_cells() and render_stl() call it up-front.
- app.py: /api/holder/render now returns 400 on ValueError (not 500)
  so the frontend can distinguish bad input from server failure.
  /api/holder/params now publishes max_cells alongside the schema.

Frontend:
- holder-app.js: reads max_cells from the params endpoint; status
  shows "N cells / over limit (1000)" in red and disables the
  Render and "Design busbars" buttons when exceeded.
- holder.css: .topbar-status.over-limit style (red, bold).
This commit is contained in:
wenil
2026-05-25 11:49:28 +03:00
parent 0aa38809b4
commit 3418e01689
4 changed files with 49 additions and 3 deletions
+13 -2
View File
@@ -19,6 +19,7 @@ const state = {
abortCtrl: null, // for cancelling in-flight render
elapsedTimer: null,
rendererReady: false,
maxCells: 1000, // server-published cap; overridden by /api/holder/params
};
// ----- viewer init ----------------------------------------------------------
@@ -218,7 +219,16 @@ function _updateStatus() {
let n;
if (style === "tria") n = rows * (rows + 1) / 2;
else n = rows * cols;
$("status").textContent = `${n} cells`;
const status = $("status");
const overLimit = n > state.maxCells;
status.textContent = overLimit
? `${n} cells · over limit (${state.maxCells})`
: `${n} cells`;
status.classList.toggle("over-limit", overLimit);
// Block render when over the cap. Also blocks "Design busbars →"
// since it'd hit the same limit on the server.
$("btn-render").disabled = overLimit;
$("btn-to-busbar").disabled = overLimit;
}
// ----- buttons --------------------------------------------------------------
@@ -299,9 +309,10 @@ async function init() {
try {
const r = await fetch("/api/holder/params");
if (!r.ok) throw new Error(r.statusText);
const { params: schema, defaults } = await r.json();
const { params: schema, defaults, max_cells } = await r.json();
state.schema = schema;
state.params = { ...defaults };
if (typeof max_cells === "number") state.maxCells = max_cells;
_renderForm(schema, defaults);
_updateStatus();
} catch (e) {