Problem description
In the policy configurator, the mathBlock expression editor (Testing → Inputs → Add Input Document → File) accepts a JSON test document and runs the expression when you press Test. With a large but realistic input document (~5 MB; a Project Description VC whose GeoJSON project boundary is ~3.5 MB with ~4,500 polygon rings / ~134k coordinate pairs) pressing Test blocks the main thread for several minutes and ends in Chrome's "Page Unresponsive" dialog or a crashed tab.
The calculation itself is not the problem: the Compute Engine evaluation of the block's variables and formulas finishes in under 300 ms, and parsing the file takes ~25 ms. The freeze happens while rendering the Results step, and two things compound:
-
The result editors render every line of the document instead of the viewport.
In frontend/src/app/modules/policy-engine/dialogs/math-editor-dialog/math-editor-dialog.component.scss the Input / Output / Errors editors sit in a 200 px .output-container (absolutely positioned, display: flex; flex-direction: column; overflow: auto). The ngx-codemirror inside it is flex: 1 and keeps the flex default min-height: auto, so it grows to the height of its own content instead of being clipped. The global rule .CodeMirror { height: 100% !important } (app.component.scss) then resolves against that grown box. Measured in the live page with a 62k‑line document: the editor box was 1,024,081 px tall, cm.getViewport() returned {from: 0, to: 62065}, and all 62,065 lines were in the DOM. CodeMirror's viewport virtualisation is fully defeated. The same page with a 643k‑line document hung for over four minutes.
-
The Input view pretty‑prints the whole document with JSON.stringify(doc, null, 4) (math-editor-dialog.component.ts, onTest). Every array element lands on its own line, so a GeoJSON coordinate list explodes: the 5 MB file becomes a 30 MB, 643,077‑line string. Combined with (1) that is 643k DOM rows.
Measurements (Chrome, dev build):
| Document |
Editor box height |
Lines rendered to DOM |
Main‑thread block |
| 62k lines, current code |
1,024,081 px |
62,065 |
~10.7 s (four long tasks) |
| 643k lines (real file), current code |
n/a, tab hung |
all |
> 4 min, then "Page Unresponsive" |
| 562k lines, with the fix below |
198 px |
21 |
~0.5 s |
Proposed fix (verified locally, all specs under math-editor-dialog pass):
math-editor-dialog.component.scss: add min-height: 0; overflow: hidden; to .output-container ngx-codemirror. This alone restores viewport rendering (21 rows instead of 62k / 643k).
- Replace
JSON.stringify(…, null, 4) for the Input / Output views with a formatter that keeps arrays on one line when their inline form is short (e.g. ≤ 100 chars: numeric tables, coordinate pairs) and otherwise breaks one element per line, objects staying one key per line. Output round‑trips through JSON.parse; for the same file it drops to 14 MB / 241k lines.
Related, not covered by the above: the Edit button on a loaded input document (add-document-dialog) pushes the whole document into the schema form and a plain <textarea>, and a textarea with a multi‑MB value blocks the main thread for 8–45 s by itself; and getItemValue(item.value) in the Results template JSON‑stringifies values on every change‑detection pass.
Step to reproduce
- Open a policy in the policy configurator and select a
mathBlock with an input schema and at least one variable/formula.
- In the block properties click the Expression property to open the expression editor.
- Go to Testing → Inputs → Add Input Document, choose File, pick a ~5 MB JSON document that contains a large array (e.g. a GeoJSON
MultiPolygon with a few hundred thousand coordinates), click Apply. The file loads fine.
- Click Test.
- The tab freezes; after a while Chrome shows "Page Unresponsive" or the tab crashes.
Expected behavior
Test completes in well under a second regardless of the input document size. The Results step shows the Input / Output JSON in a scrollable editor that renders only the visible lines, so a multi‑MB test document is as usable as a small one.
Screenshots

Problem description
In the policy configurator, the
mathBlockexpression editor (Testing → Inputs → Add Input Document → File) accepts a JSON test document and runs the expression when you press Test. With a large but realistic input document (~5 MB; a Project Description VC whose GeoJSON project boundary is ~3.5 MB with ~4,500 polygon rings / ~134k coordinate pairs) pressing Test blocks the main thread for several minutes and ends in Chrome's "Page Unresponsive" dialog or a crashed tab.The calculation itself is not the problem: the Compute Engine evaluation of the block's variables and formulas finishes in under 300 ms, and parsing the file takes ~25 ms. The freeze happens while rendering the Results step, and two things compound:
The result editors render every line of the document instead of the viewport.
In
frontend/src/app/modules/policy-engine/dialogs/math-editor-dialog/math-editor-dialog.component.scssthe Input / Output / Errors editors sit in a 200 px.output-container(absolutely positioned,display: flex; flex-direction: column; overflow: auto). Thengx-codemirrorinside it isflex: 1and keeps the flex defaultmin-height: auto, so it grows to the height of its own content instead of being clipped. The global rule.CodeMirror { height: 100% !important }(app.component.scss) then resolves against that grown box. Measured in the live page with a 62k‑line document: the editor box was 1,024,081 px tall,cm.getViewport()returned{from: 0, to: 62065}, and all 62,065 lines were in the DOM. CodeMirror's viewport virtualisation is fully defeated. The same page with a 643k‑line document hung for over four minutes.The Input view pretty‑prints the whole document with
JSON.stringify(doc, null, 4)(math-editor-dialog.component.ts,onTest). Every array element lands on its own line, so a GeoJSON coordinate list explodes: the 5 MB file becomes a 30 MB, 643,077‑line string. Combined with (1) that is 643k DOM rows.Measurements (Chrome, dev build):
Proposed fix (verified locally, all specs under
math-editor-dialogpass):math-editor-dialog.component.scss: addmin-height: 0; overflow: hidden;to.output-container ngx-codemirror. This alone restores viewport rendering (21 rows instead of 62k / 643k).JSON.stringify(…, null, 4)for the Input / Output views with a formatter that keeps arrays on one line when their inline form is short (e.g. ≤ 100 chars: numeric tables, coordinate pairs) and otherwise breaks one element per line, objects staying one key per line. Output round‑trips throughJSON.parse; for the same file it drops to 14 MB / 241k lines.Related, not covered by the above: the Edit button on a loaded input document (
add-document-dialog) pushes the whole document into the schema form and a plain<textarea>, and a textarea with a multi‑MB value blocks the main thread for 8–45 s by itself; andgetItemValue(item.value)in the Results template JSON‑stringifies values on every change‑detection pass.Step to reproduce
mathBlockwith an input schema and at least one variable/formula.MultiPolygonwith a few hundred thousand coordinates), click Apply. The file loads fine.Expected behavior
Test completes in well under a second regardless of the input document size. The Results step shows the Input / Output JSON in a scrollable editor that renders only the visible lines, so a multi‑MB test document is as usable as a small one.
Screenshots