Instead of a separate node, _get_data now appends three derived keys
to every sequence response: Path(start frame path).stem → start_name,
etc. Any ProjectKey node can use these directly as key_name.
Reverts ProjectFrameNames node (unnecessary).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
New node in JSON Manager/project that fetches start/middle/end frame
path from the sequence and outputs Path(value).stem for each, so
e.g. '/path/to/keyframe8.png' → 'keyframe8'. Avoids manual string
filtering in large workflows.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Added /api/active-project endpoint that reads current_project from
config. ProjectSource now hides the project_name widget and fetches
the active project automatically on create, load, and click.
Title shows "Source: <label> [<project>]" for at-a-glance status.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clicking any ProjectKey node temporarily highlights all other nodes
in the workflow that share the same key_name with an amber color.
Deselecting restores their original colors.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
API returns {"files": [{"name": "...", "data_type": "..."}]}, not a
plain array. Extract file names from the nested structure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- file_name is now a combo dropdown populated from the API when
manager_url and project_name are set
- ProjectSource outputs sequence_number (INT) for downstream use
- Refreshes file list when project_name or manager_url changes
- Updated tests for new output and error-default behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When ProjectKey configures before ProjectSource, _getSourceLabels
returns empty. replaceWithCombo now always keeps the saved value in
the options list so it survives the race condition.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The key_name combo now only updates its dropdown options from the API
but never changes the user's selected value. Only the output value
refreshes on execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The async _refreshKeys call on every mouse click caused a race condition
where clicking the key_name dropdown would trigger a re-fetch that
overwrote the user's selection. Keys are now only refreshed on source
label change and workflow load.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProjectKey.fetch_key now returns empty defaults instead of raising
RuntimeError on API errors. Added logging to _syncFromSource and
fetch_key to trace the seq=4001 vs seq=4 mismatch.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
ProjectKey onMouseDown now triggers _syncFromSource + _refreshKeys so
clicking a relay always picks up source config changes. Added console
logs to notifyRelays and _refreshKeys for diagnosing sync issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When ProjectSource widgets (url, project, file, sequence_number)
change, all ProjectKey nodes referencing that source now re-sync
and refresh their key dropdown immediately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Combo widgets show "undefined" when values list is empty. Now ensures
at least one entry (empty string placeholder) and picks a valid default.
Also populates source labels immediately on node creation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- INT widgets (sequence_number) now properly hidden using origType +
hidden flag pattern from fast_saver.js
- source_label and key_name are now replaced with real combo widgets
via addWidget("combo") instead of just setting type="combo" on
STRING widgets, which didn't produce working dropdowns
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add bounds check on src_batch index in add_from_source and copy_source
- Guard delete callback against stale index after rapid clicks
- Replace __import__('time').time() with time.time() in sync_to_db
- Use deepcopy(DEFAULTS) consistently in utils.py and main.py
- Use JSON.stringify in JS onConfigure fallback path for key storage
- Read state.show_comfy_monitor for checkbox initial value
- Remove unused KEY_BATCH_DATA import from tab_projects_ng
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use asyncio.to_thread for proxy endpoints to avoid blocking event loop
- Add mode to DEFAULTS so it doesn't silently insert 0
- Use JSON serialization for keys in project_dynamic.js (with comma fallback)
- Validate path exists in change_path, friendly error on duplicate rename
- Remove unused exp param from rename closure
- Use deepcopy for DEFAULTS consistently
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Changing the refresh value triggers the node to re-fetch keys from
the API, picking up any new or modified fields in the data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The actual fix was setting slot.label alongside slot.name. Reverted
onConfigure to read from widget values (which work correctly) and
ensured label is set on both new and reused output slots.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LiteGraph renders slot.label over slot.name — we were updating name
but the display uses label.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Read output names from info.outputs (serialized node data) instead of
hidden widget values, which ComfyUI may not persist across reloads.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The separate ComfyUI-JSON-Dynamic extension provides the same node.
Removes json_loader.py, web/json_dynamic.js, and their tests. Only
ProjectLoaderDynamic remains in this extension.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
JSON.stringify format for hidden widget values didn't survive ComfyUI's
serialization round-trip. Switch to comma-separated strings matching
the proven ComfyUI-JSON-Dynamic implementation. Remove properties-based
approach in favor of the simpler, working pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Hidden widget values for output_keys/output_types were not reliably
restored by ComfyUI on workflow reload. Store keys/types in
node.properties (always persisted by LiteGraph) as primary storage,
with hidden widgets as fallback.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove 3 redundant hardcoded nodes (Standard/VACE/LoRA), keeping only the
Dynamic node. Add total_sequences INT output (slot 0) for loop counting.
Add structured error handling: _fetch_json returns typed error dicts,
load_dynamic raises RuntimeError with descriptive messages, JS shows
red border/title on errors. Add 500ms debounced auto-refresh on widget
changes. Add 404s for missing project/file in API endpoints.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix delete_proj not persisting cleared current_project to config:
page reload after deleting active project restored deleted name,
silently breaking all DB sync
- Fix sync_to_db crash on non-dict batch_data items: add isinstance
guard matching import_json_file
- Fix output_types ignored in load_dynamic: parse declared types and
use to_int()/to_float() to coerce values, so downstream ComfyUI
nodes receive correct types even when API returns strings
- Fix backward-compat comma-split for types not trimming whitespace:
legacy workflows with "STRING, INT" got types " INT" breaking
ComfyUI connection type-matching
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
HIGH:
- Fix JS TypeError on empty API response: validate keys/types are arrays
before using them; add HTTP status check (resp.ok)
- Fix BEGIN IMMEDIATE conflict: set isolation_level=None (autocommit) on
SQLite connection so explicit transactions work without implicit ones
MEDIUM:
- Fix import_json_file non-atomic: wrap entire operation in BEGIN/COMMIT
with ROLLBACK on error — no more partial imports
- Fix crash on non-dict batch_data items: skip non-dict elements
- Fix comma-in-key corruption: store keys/types as JSON arrays in hidden
widgets instead of comma-delimited strings (backward-compat fallback)
- Fix blocking I/O in API routes: change async def to def so FastAPI
auto-threads the synchronous SQLite calls
LOW:
- Fix missing ?. on app.graph.setDirtyCanvas in refreshDynamicOutputs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Deferred output cleanup (_configured flag + queueMicrotask) to prevent
breaking links when other nodes (e.g. Kijai Set/Get) resolve outputs
during graph loading
- file_not_found error handling in refresh to keep existing outputs intact
- Fallback widget sync in onConfigure when widget values are empty but
serialized outputs exist
Applied to both json_dynamic.js and project_dynamic.js.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- db.py: ProjectDB class with SQLite schema (projects, data_files,
sequences, history_trees), WAL mode, CRUD, import, and query helpers
- api_routes.py: REST API endpoints on NiceGUI/FastAPI for ComfyUI
to query project data over the network
- project_loader.py: ComfyUI nodes (ProjectLoaderDynamic, Standard,
VACE, LoRA) that fetch data from NiceGUI REST API via HTTP
- web/project_dynamic.js: Frontend JS for dynamic project loader node
- tab_projects_ng.py: Projects management tab in NiceGUI UI
- state.py: Added db, current_project, db_enabled fields
- main.py: DB init, API route registration, projects tab
- utils.py: sync_to_db() dual-write helper
- tab_batch_ng.py, tab_raw_ng.py, tab_timeline_ng.py: dual-write
sync calls after save_json when project DB is enabled
- __init__.py: Merged project node class mappings
- tests/test_db.py: 30 tests for database layer
- tests/test_project_loader.py: 17 tests for ComfyUI connector nodes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Types were lost on workflow reload because only key names were stored.
Now both keys and types are saved in hidden widgets and restored by
onConfigure, so colored connector dots persist without needing Refresh.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
API route now returns types alongside keys. JS sets output slot type
accordingly, giving correct colored dots and type-safe connections.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diff new keys against existing outputs instead of remove-all/add-all.
Reuses slot objects for matching key names so links stay connected.
Only disconnects links on keys that were actually removed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Direct array manipulation bypassed LiteGraph's internal slot tracking,
causing output names to show as defaults instead of JSON key names.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Dynamic node reads JSON keys and exposes them as outputs automatically
via 32 AnyType slots managed by a JS extension (show/hide/rename).
Includes /json_manager/get_keys API route, bool-safe type handling,
and workflow save/reload support.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>