Files
malkuthro-ComfyUI-Koolook/docs/maintainers/workflows-sidebar.md
T
malkuthroandClaude Opus 4.7 e03523faf9 refactor(web): split koolook_sidebar.js into 7 sidebar modules (#51)
* refactor(web): split koolook_sidebar.js into 7 sidebar modules

Pure mechanical split — zero behavior change. Implements the design from
issue #49 (common-case layout with patchCanvasMenu extracted).

Old: web/koolook_sidebar.js (1973 lines, monolithic)
New: web/koolook_sidebar.js (48-line entry) + 7 modules in web/sidebar/

  - constants.js (130) — REPOS, TAB_*, storage keys, event names, URLs,
    ensureStyle, toast, compareNames
  - picks_store.js (117) — localStorage user picks: load/save/add (tri-state)
    /remove/notify/seed/export
  - workflows_store.js (347) — workflowsCache + persistMutation + snapshotCache
    + commit + persist*/load*/seed* + in-memory ops; cache is module-private
  - canvas_io.js (192) — serialize*/canvasIsNonEmpty/loadWorkflowOntoCanvas
    /insertNode/getSelectedNodeTypes
  - modals.js (384) — makeModalShell + showInputModal/showConfirmModal
    /showSaveWorkflowModal/showContextMenu
  - canvas_menu.js (45) — patchCanvasMenu (idempotent LGraphCanvas patch)
  - tree.js (825) — pathStates (module-private) + gatherers + DOM row
    factories + buildFolder + workflow/dir context menus + rebuildTree
    + renderPanel

Encapsulation invariants verified:
  - workflowsCache: zero references outside workflows_store.js
  - pathStates: zero references outside tree.js
  - All 8 files pass node --check
  - CSS string byte-identical to original
  - URL constants resolve to same targets after the extra `..` adjustment

Documentation updated: dev-iteration-loop.md and workflows-sidebar.md
now point pathStates references at web/sidebar/tree.js. Other doc
references to koolook_sidebar.js as the entry remain accurate.

Closes #49.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(web): drop unreachable defensive guard in gatherWorkflows

Review feedback on #51: the `if (!dir) continue;` after `dirOf(dirName)`
is unreachable — `listDirectoryNames()` enumerates the same module-private
`workflowsCache.directories` keys that `dirOf()` reads, synchronously,
within a single event-loop turn. Removing the guard restores strict
"byte-identical move" semantics for the file-split refactor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 17:47:20 +02:00

3.6 KiB

Workflows sidebar — quick reference

The "Workflows" section of the Curated Nodes sidebar tab; implementation shares web/koolook_sidebar.js with the Curated Nodes feature.

Save / load loop

  1. Click 💾 (whole canvas) or ✂ (selection only) in the Workflows action bar.
  2. Modal: Directory → Base on existing (optional) → Action → Workflow name (shown only when needed).
  3. Saved entry appears at the bottom of its directory in the tree.
  4. Click any workflow row to load it onto a fresh tab; the tab title takes the workflow's name.

Action semantics

Action Resulting name Archive behavior
New name typed auto-archives only if the typed name happens to collide
Use existing name (archive previous) base always archives the existing entry
Modify existing name base, edited no archive (different name)

The archive trigger is a name collision with any existing active entry, regardless of which action was selected. The Action dropdown is UX guidance; the underlying logic flows from the resulting (name, dir) pair.

Right-click menus

  • Workflow row: Load / Rename / → <other dir> / Move to archive (or Restore from archive if already archived) / Delete.
  • Directory row: Rename / Delete (with confirm if non-empty).

Storage

Where What
/userdata/koolook_workflows.json (ComfyUI install) Primary. Per-install.
localStorage["koolook.workflows.fallback.v1"] Used only if /userdata is unreachable.
localStorage["koolook.workflows.seeded.v1"] "1" once defaults have been seeded for this install.
web/workflow_defaults.json (in repo) Distributed starter pack — seeded once into /userdata on first load with empty workflow data.

JSON shape:

{
  "directories": {
    "<dir>": {
      "workflows": {
        "<name>": {
          "savedAt": "<ISO timestamp>",
          "graph": { /* serialized ComfyUI workflow JSON */ },
          "archived": true
        }
      }
    }
  }
}

archived is optional (false/missing means active).

Reset (force re-seed from defaults)

Delete the userdata file in the live ComfyUI install:

rm <ComfyUI>/user/default/userdata/koolook_workflows.json

Then in the ComfyUI page DevTools console:

localStorage.removeItem("koolook.workflows.seeded.v1");
localStorage.removeItem("koolook.workflows.fallback.v1");
location.reload();

Things that surprised us — keep in mind

  • Selection saves are partial graphs. Only the selected nodes + links between them survive; links into/out of non-selected nodes are nulled out, so the loaded workflow never has dangling references.
  • Workflow tab name comes from app.loadGraphData(graph, true, true, name, {})'s 4th arg. The tab flips from "Unsaved Workflow (N)" to the saved name, and Ctrl+S pre-fills with that name. (Verified against Comfy-Org/ComfyUI_frontend src/scripts/app.ts.)
  • Folder expansion state persists across re-renders (the pathStates Map in web/sidebar/tree.js). Saving never collapses the directory you were viewing.
  • Archive sub-folder is rendered above active workflows in each directory, so the latest active workflow sits closest to the bottom — easy to spot.
  • No auto-pruning of archives. Re-saving the same name many times leaves many timestamped archive entries. Right-click → Delete to remove individual ones when no longer useful.
  • Same-pattern distribution as curated_defaults.json — see curated-sidebar.md for the seeding semantics that also apply here.