Files
PozzettiAndrea-ComfyUI-Geom…/javascript/js/text_report.js
T
PozzettiAndrea 414f759791 Vendor frontend JS into javascript/; drop the prestartup copy dance
The viewer JS/HTML/bundles are now committed in javascript/ (declared via
pyproject [tool.comfy] web = "javascript") instead of being copied from the
shared comfy-3d-viewers pip package at prestartup. Consequences:

- requirements.txt is now just comfy-env (host env installs nothing else,
  per the never-touch-the-host-env principle)
- prestartup_script.py no longer copies viewers or web_src; it keeps only
  setup_env() and the input-asset copies
- WEB_DIRECTORY attribute removed; the pyproject declaration is the single
  source (served at /extensions/comfyui-geometrypack/, keyed by project name)
- web_src/ deleted; its 6 widgets now live in javascript/js/ as the tracked
  source, edited directly
- viewer_pbr.html hardcoded-fallback URL updated to the new mount name

Iframe URLs auto-detect the mount from import.meta.url, so the folder rename
and mount-name change are transparent at runtime.
2026-08-12 17:37:09 +02:00

186 lines
6.2 KiB
JavaScript

/**
* ComfyUI GeomPack - Generic Text Report Renderer
* Collapsible info panel. Arrow toggle at top of box.
*/
import { app } from "../../../scripts/app.js";
import { buildTextReportHTML } from "./utils/analysisPanel.js";
const TEXT_REPORT_NODES = [
// CADabra
"CADUltimateInspection",
// Analysis
"GeomPackMeshInfo",
"GeomPackMeshQuality",
"GeomPackDegenerateFaces",
"GeomPackConnectedComponents",
"GeomPackOpenEdges",
"GeomPackComputeCurvature",
"GeomPackSegmentByCurvature",
"GeomPackComputeFilletField",
"GeomPackSegmentPatches",
"GeomPackClusterFaces",
// Repair
"GeomPackFillHoles",
"GeomPackMeshFix",
"GeomPackCheckNormals",
"GeomPackFixNormals",
"GeomPackMeshRepair",
"GeomPackRemoveDegenerateFaces",
"GeomPackMergeVertices",
"GeomPackVisualizeNormals",
"GeomPackAddNormalsToPointCloud",
"GeomPackFixSelfIntersectionsByRemoval",
"GeomPackDetectSelfIntersections",
"GeomPackFixSelfIntersectionsByPerturbation",
"GeomPackRemeshSelfIntersections",
// Smoothing / Decimation (unified dispatcher front nodes — info forwarded
// from the hidden backend via the executed event's display_node)
"GeomPackSharpenMesh",
"GeomPackDecimateMesh",
// Remeshing
"GeomPackRemesh",
"GeomPackRemeshCGAL",
"GeomPackRemeshBlender",
"GeomPackRemeshGPU",
"RefineMesh",
"GeomPackEdgeFlip",
// Reconstruction
"GeomPackReconstructSurface",
"GeomPackAlphaWrap",
// Texture remeshing
"GeomPackTextureToGeometry",
"GeomPackDepthNormalsToMesh",
"GeomPackRemeshWithTexture",
// Boolean
"GeomPackBooleanCGAL",
"GeomPackBooleanBlender",
// Combine
"GeomPackCombineMeshes",
"GeomPackCombineMeshesBatch",
"GeomPackSplitByField",
// Transforms
"GeomPackTransformMesh",
"GeomPackNormalizeMeshToBBox",
// UV
"GeomPackUVUnwrap",
// Distance
"GeomPackPointToMeshDistance",
"GeomPackMeshToMeshDistance",
// IO
"GeomPackLoadMeshFBX",
"GeomPackLoadMeshBlend",
// CADabra
"CADEdgeAnalysis",
"CAD_Quality_Metrics",
"CADCurvature",
"CADSewFaces",
"CADCheckOverlappingFaces",
"CADSplitComponents",
"CADHealShape",
"CADFixDegenerateFaces",
"CADPrimitiveReconstruction",
"CADFaceAnalysis",
// MeshSegmenter
"MeshSegGenerateMasks",
"MeshSegLift2DTo3DLabels",
"MeshSegSmoothLabels",
"MeshSegApplyLabelsToMesh",
];
const TOGGLE_HEIGHT = 28;
const DEFAULT_CONTENT_HEIGHT = 60;
app.registerExtension({
name: "geompack.text_report",
async beforeRegisterNodeDef(nodeType, nodeData, app) {
if (!TEXT_REPORT_NODES.includes(nodeData.name)) return;
const onNodeCreated = nodeType.prototype.onNodeCreated;
nodeType.prototype.onNodeCreated = function() {
const r = onNodeCreated ? onNodeCreated.apply(this, arguments) : undefined;
let expanded = false;
let contentHeight = DEFAULT_CONTENT_HEIGHT;
let widgetHeight = TOGGLE_HEIGHT;
const node = this;
// --- Single container widget ---
const container = document.createElement("div");
container.style.cssText = "background:#1a1a2e; border:1px solid #333; border-radius:4px; overflow:hidden; display:flex; flex-direction:column; height:100%;";
// Header bar (always visible, top of box)
const header = document.createElement("div");
header.style.cssText = "display:flex; align-items:center; gap:6px; padding:2px 8px; cursor:pointer; user-select:none; font-size:11px; color:#888; flex-shrink:0;";
const arrow = document.createElement("span");
arrow.style.cssText = "font-size:8px; display:inline-block; transition:transform 0.15s;";
arrow.textContent = "\u25B6";
const label = document.createElement("span");
label.textContent = "Info";
header.appendChild(arrow);
header.appendChild(label);
// Content area (hidden when collapsed)
const content = document.createElement("div");
content.style.cssText = "padding:6px 8px; border-top:1px solid #333; font-size:11px; color:#ccc; display:none; overflow-y:auto; flex:1; min-height:0;";
container.appendChild(header);
container.appendChild(content);
// Use getMinHeight/getHeight — the API ComfyUI's DOMWidgetImpl actually reads
const widget = this.addDOMWidget("report_panel", "REPORT_PANEL", container, {
getValue() { return expanded ? "true" : "false"; },
setValue(v) { if (v === "true") setExpanded(true); },
getMinHeight: () => widgetHeight,
getHeight: () => widgetHeight,
});
// Force node to grow to fit the widget
requestAnimationFrame(() => {
node.setSize([node.size[0], node.computeSize()[1]]);
node.setDirtyCanvas(true, true);
});
function resize() {
widgetHeight = expanded ? TOGGLE_HEIGHT + contentHeight : TOGGLE_HEIGHT;
node.setSize([node.size[0], node.computeSize()[1]]);
node.setDirtyCanvas(true, true);
}
function setExpanded(val) {
expanded = val;
content.style.display = expanded ? "block" : "none";
arrow.style.transform = expanded ? "rotate(90deg)" : "";
resize();
}
// Toggle click
header.addEventListener("click", () => {
setExpanded(!expanded);
});
// Execution results
const onExecuted = this.onExecuted;
this.onExecuted = function(message) {
onExecuted?.apply(this, arguments);
if (message?.text && message.text.length > 0) {
const text = message.text[0];
content.innerHTML = buildTextReportHTML(text);
const firstLine = text.split("\n")[0].trim();
if (firstLine) label.textContent = firstLine;
resize();
}
};
return r;
};
}
});