From d93d36e8ad23a0307dd4d7d9f989c4d7ee07bc39 Mon Sep 17 00:00:00 2001 From: Kamil Patryk Kozakowski Date: Thu, 18 Jun 2026 22:06:57 +0200 Subject: [PATCH] html exporter fixed --- .../exporter/ExportOptions.java | 2 + .../html/command/HtmlExporterCommand.java | 8 +++ .../html/exporter/HtmlExporter.java | 41 ++++++++++++- .../src/main/resources/html/template.html | 59 +++++++------------ 4 files changed, 72 insertions(+), 38 deletions(-) diff --git a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/exporter/ExportOptions.java b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/exporter/ExportOptions.java index 6eecf77..7813517 100644 --- a/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/exporter/ExportOptions.java +++ b/state_machine_exporter/src/main/java/click/kamil/springstatemachineexporter/exporter/ExportOptions.java @@ -12,6 +12,8 @@ public class ExportOptions { boolean renderChoicesAsDiamonds = true; @Builder.Default boolean embedIdentifiers = false; + @Builder.Default + boolean includeMetadataPane = true; @Builder.Default EnumFormat eventFormat = EnumFormat.fn; diff --git a/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/command/HtmlExporterCommand.java b/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/command/HtmlExporterCommand.java index 52d3cd2..9e1303f 100644 --- a/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/command/HtmlExporterCommand.java +++ b/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/command/HtmlExporterCommand.java @@ -56,6 +56,9 @@ public class HtmlExporterCommand implements Callable { @Option(names = {"--no-diamonds"}, description = "Disable rendering choice pseudostates as PlantUML diamonds (render them as normal state nodes instead).") private boolean noDiamonds; + @Option(names = {"--no-metadata-pane"}, description = "Disable rendering the left metadata pane (entry points, flows) in the HTML viewer.") + private boolean noMetadataPane; + @Override public Integer call() throws Exception { var out = spec.commandLine().getOut(); @@ -78,12 +81,17 @@ public class HtmlExporterCommand implements Callable { List formats = List.of("html", "json"); List profiles = activeProfiles != null ? activeProfiles : java.util.Collections.emptyList(); + if (noMetadataPane) { + System.setProperty("html.hideMetadataPane", "true"); + } + if (jsonFile != null) { exportService.runJsonExporter(jsonFile, outputDir, formats, profiles); } else { boolean renderChoicesAsDiamonds = !noDiamonds; exportService.runExporter(inputDir, outputDir, formats, renderChoicesAsDiamonds, profiles, flowsFile, machineFilter); } + System.clearProperty("html.hideMetadataPane"); out.println(CommandLine.Help.Ansi.AUTO.string("%n@|bold,green SUCCESS:|@ Interactive documentation generated successfully.")); diff --git a/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/exporter/HtmlExporter.java b/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/exporter/HtmlExporter.java index c2bf95e..0a4165b 100644 --- a/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/exporter/HtmlExporter.java +++ b/state_machine_exporter_html/src/main/java/click/kamil/springstatemachineexporter/html/exporter/HtmlExporter.java @@ -56,12 +56,51 @@ public class HtmlExporter implements StateMachineExporter { // 5. Prepare Metadata JSON String metadataJson = objectMapper.writeValueAsString(result); + // Check if we should render metadata pane + boolean hideMetadataProp = Boolean.getBoolean("html.hideMetadataPane"); + boolean hasEntryPoints = result.getMetadata() != null && result.getMetadata().getEntryPoints() != null && !result.getMetadata().getEntryPoints().isEmpty(); + boolean hasFlows = result.getFlows() != null && !result.getFlows().isEmpty(); + boolean shouldRenderPane = !hideMetadataProp && options.isIncludeMetadataPane() && (hasEntryPoints || hasFlows); + // 6. Inject Data - return template + String finalHtml = template .replace("{{MACHINE_NAME}}", result.getName()) .replace("{{SVG_CONTENT}}", decoratedSvg) .replace("{{METADATA_JSON}}", metadataJson); + if (shouldRenderPane) { + // If template.html uses {{SIDEBAR_HTML}} and {{TOGGLE_BUTTON_HTML}}, replace with actual HTML + finalHtml = finalHtml.replace("{{SIDEBAR_HTML}}", "
\n" + + "
\n" + + "
\n" + + "

Explorer

\n" + + "

{{MACHINE_NAME}}

\n" + + "
\n" + + "
\n" + + " \n" + + "
\n" + + "
Explorer
\n" + + "
Business Flows
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "\n" + + "
\n" + + "
\n" + + "
\n" + + "
").replace("{{MACHINE_NAME}}", result.getName()); + + finalHtml = finalHtml.replace("{{TOGGLE_BUTTON_HTML}}", " "); + } else { + finalHtml = finalHtml.replace("{{SIDEBAR_HTML}}", "").replace("{{TOGGLE_BUTTON_HTML}}", ""); + } + + return finalHtml; + } catch (Exception e) { log.error("Failed to export to HTML", e); throw new RuntimeException("HTML export failed", e); diff --git a/state_machine_exporter_html/src/main/resources/html/template.html b/state_machine_exporter_html/src/main/resources/html/template.html index 270c073..65db1a2 100644 --- a/state_machine_exporter_html/src/main/resources/html/template.html +++ b/state_machine_exporter_html/src/main/resources/html/template.html @@ -261,32 +261,10 @@ - +{{SIDEBAR_HTML}}
- + {{TOGGLE_BUTTON_HTML}}
{{SVG_CONTENT}}
@@ -304,18 +282,21 @@ const svg = document.querySelector('#svg-container svg'); panZoomInstance = svgPanZoom(svg, { zoomEnabled: true, controlIconsEnabled: true, fit: true, center: true }); - document.getElementById('toggle-sidebar').addEventListener('click', () => { - const sidebar = document.getElementById('sidebar'); - sidebar.classList.toggle('collapsed'); - - // Re-center SVG pan-zoom after transition - setTimeout(() => { - if (panZoomInstance) { - panZoomInstance.resize(); - panZoomInstance.center(); - } - }, 300); - }); + const toggleSidebar = document.getElementById('toggle-sidebar'); + if (toggleSidebar) { + toggleSidebar.addEventListener('click', () => { + const sidebar = document.getElementById('sidebar'); + if (sidebar) sidebar.classList.toggle('collapsed'); + + // Re-center SVG pan-zoom after transition + setTimeout(() => { + if (panZoomInstance) { + panZoomInstance.resize(); + panZoomInstance.center(); + } + }, 300); + }); + } setupTabs(); populateSidebar(); @@ -325,8 +306,10 @@ function setupTabs() { const flows = metadata.flows || []; + const tabsEl = document.querySelector('.tabs'); + if (!tabsEl) return; if (flows.length === 0) { - document.querySelector('.tabs').style.display = 'none'; + tabsEl.style.display = 'none'; document.querySelector('.tab-content[data-tab="flows"]')?.remove(); return; } @@ -342,6 +325,7 @@ function populateSidebar() { const list = document.getElementById('ep-list'); + if (!list) return; const entryPoints = metadata.metadata.entryPoints || []; const machineEvents = new Set(metadata.transitions.map(t => t.event).filter(Boolean)); @@ -372,6 +356,7 @@ function populateFlows() { const list = document.getElementById('flow-list'); + if (!list) return; const flows = metadata.flows || []; if (flows.length === 0) {