html_generator.get_html_template now emits a shell (empty fullManifest flagged __uscg_lazy__, inline_manifest=True restores the old behaviour). New route GET /config_tester/manifest?session=<name>: compact JSON, weak ETag, 304 on If-None-Match, gzip, torn-read retry (logic in run_api.load_manifest_for_fetch). /config_tester/dashboard gets gzip + content ETag. The SPA boots with one fetch (no more double load), resync is conditional and non-destructive, and web/dashboard.js asks the iframe to re-fetch (reload_manifest) instead of parsing data out of the Generator's executed message. Also fixes the dead session-name regex in dashboard_node.py. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
80 lines
3.8 KiB
Python
80 lines
3.8 KiB
Python
import os
|
|
import json
|
|
|
|
def get_html_template(title, manifest_data, node_id, standalone=False, inline_manifest=False):
|
|
"""Build the dashboard page.
|
|
|
|
By default the page is a SHELL: no item data is inlined (an empty `fullManifest` flagged
|
|
`__uscg_lazy__`), and the SPA fetches `/config_tester/manifest?session=<title>` itself. That
|
|
keeps the HTML (and ComfyUI's `executed` websocket message / history entry, which carries the
|
|
whole string) ~500 KB instead of growing with the session. `manifest_data` is only used when
|
|
`inline_manifest=True` (old behaviour; offline export / tests).
|
|
"""
|
|
# 1. Normalize Data
|
|
if not inline_manifest:
|
|
manifest_data = {"items": [], "meta": {"model": "", "positive": "", "negative": ""},
|
|
"session_name": str(title), "__uscg_lazy__": True}
|
|
elif isinstance(manifest_data, list):
|
|
manifest_data = {"items": manifest_data, "meta": {"model": "", "positive": "", "negative": ""}}
|
|
|
|
# Indent JSON for readability
|
|
json_str = json.dumps(manifest_data, indent=2)
|
|
# The manifest is inlined inside a <script> element: a note/prompt containing "</script>" would
|
|
# end it early (page break / script injection). "<\/" is an equivalent JSON escape, so
|
|
# JSON.parse (web/dashboard.js's incremental refresh) still reads the original text.
|
|
json_str = json_str.replace("</", "<\\/")
|
|
|
|
# 2. Resolve File Paths
|
|
current_dir = os.path.dirname(__file__)
|
|
resource_dir = os.path.join(current_dir, "resources")
|
|
|
|
# Define JS Load Order (Dependencies first!)
|
|
js_files = [
|
|
"logic_state.js", # Global variables
|
|
"logic_utils.js", # API & Helper functions
|
|
"logic_ratings.js", # Pairwise review: pure logic (normalisers, Bradley-Terry, pairing, scoreboard)
|
|
"logic_wfparams.js", # Workflow Sweep: wf_params helpers (pure; must load before logic_ui/logic_pipeline)
|
|
"logic_dragdrop.js", # Revise-modal image drag/send helpers (issue #22; pure, node-testable)
|
|
"logic_ui.js", # DOM Creation, Modals, JSON Bars
|
|
"logic_upscale_modal.js", # Upscale Modal (preset management, async upscale)
|
|
"logic_virtual.js", # The Virtual Scroll Engine & Viewport
|
|
"logic_pipeline.js", # Sorting & Filtering Logic
|
|
"logic_compare.js", # Pairwise review: compare overlay, votes, scoreboard modal
|
|
"logic_events.js", # Event Listeners (Message, Keyboard)
|
|
"logic_init.js", # Initialization
|
|
"logic_standalone.js" # Standalone-page mode (own websocket, run API); must stay LAST
|
|
]
|
|
|
|
try:
|
|
# Load HTML
|
|
with open(os.path.join(resource_dir, "template.html"), "r", encoding="utf-8") as f:
|
|
html_template = f.read()
|
|
|
|
# Load CSS
|
|
with open(os.path.join(resource_dir, "report.css"), "r", encoding="utf-8") as f:
|
|
css_content = f.read()
|
|
|
|
# Load and Concatenate JS
|
|
js_content = ""
|
|
for js_file in js_files:
|
|
file_path = os.path.join(resource_dir, js_file)
|
|
with open(file_path, "r", encoding="utf-8") as f:
|
|
js_content += f"\n/* --- {js_file} --- */\n"
|
|
js_content += f.read() + "\n"
|
|
|
|
except FileNotFoundError as e:
|
|
return f"<h1>Error: Resource files not found.</h1><p>{e}</p>"
|
|
|
|
# 3. Inject Data
|
|
wrapped_json = f"/*__JSON_START__*/\nlet fullManifest = {json_str};\n/*__JSON_END__*/"
|
|
|
|
# 4. Final Replacements
|
|
final_html = html_template \
|
|
.replace("__TITLE__", str(title)) \
|
|
.replace("__NODE_ID__", str(node_id)) \
|
|
.replace("__STANDALONE_FLAG__", "true" if standalone else "false") \
|
|
.replace("let fullManifest = __JSON_DATA__;", wrapped_json) \
|
|
.replace("__CSS_CONTENT__", css_content) \
|
|
.replace("__JS_CONTENT__", js_content)
|
|
|
|
return final_html |