diff --git a/.agents/logs/ai_changelog.md b/.agents/logs/ai_changelog.md index 6ae7eb4..8aa71c0 100644 --- a/.agents/logs/ai_changelog.md +++ b/.agents/logs/ai_changelog.md @@ -406,4 +406,28 @@ ## [2026-08-03] UI 重构与架构精简 - **Recipe UI 现代化**: 合并了冗杂的 Tabs,将 模型与复现 和 参数 合并进入 概览 面板,并将底层参数收入折叠组件,极大减轻了信息噪音。 - **配方卡片列表降噪**: 移除了原配方列表卡片上的全量参数展示,仅保留封面图、标题、标签与模型徽章,并重构了操作按钮布局。 -- **交互逻辑修复**: 废弃了极易出 Bug 的 Quick Queue 逻辑,统一了『打开到画布』与『追加到画布』的逻辑封装。 +- **交互逻辑修复**: 废弃了极易出 Bug 的 Quick Queue 逻辑,统一了『打开到画布』与『追加到画布』的逻辑封装。 + +## [Snapshot] 2026-08-03 - Recipe schema v5 origin extraction and rendering +**Implemented** +- Separated model physical filenames from official C-site origin names. +- Updated get_metadata to export model_id and version_id. +- Recipes now store origin info when saving/updating. +- UI prioritizes origin.model_name and provides a Civitai link if available. +- Added refresh identities button for older recipes. +- Localized identity phrases to be more human-centric. + +## [Snapshot] 2026-08-03 - Fix Workspace reopen blank state and recipe identity compatibility + +**Implemented** + +- Rehydrated the notebook body and active section when reopening an already initialized Workspace after close. +- Kept recipe body hidden while reopening the default notebook section, preventing an empty Workspace overlay. +- Made recipe model-reference enrichment accept both the new identity-plus-origin helper result and the legacy identity-only contract. + +**Validation** + +- `node --check web/main.js web/modules/ui_notebooks.js web/modules/ui_sidebar.js web/modules/ui_recipes.js` +- `python_embeded/python.exe -m py_compile api/recipes.py api/metadata.py` +- `node tests/recipe_parser_roundtrip.mjs` +- `python_embeded/python.exe tests/test_recipe_roundtrip.py` diff --git a/.agents/logs/ai_lessons.md b/.agents/logs/ai_lessons.md index f7b5b8b..73f1532 100644 --- a/.agents/logs/ai_lessons.md +++ b/.agents/logs/ai_lessons.md @@ -13,6 +13,10 @@ Opening a detail panel should capture the list's semantic location and viewport, ## 58. Overlay Close Must Restore Its Covered Panel An overlay that only toggles its own visibility can reveal a blank host surface if the underlying panel was hidden by an earlier navigation path. Record the covered panel at overlay entry and restore it through one shared close function. Keep a safe visible fallback, such as the main grid, for stale or missing return state. + +## 59. Reused Overlay DOM Must Be Rehydrated on Reopen + +When an overlay is closed by hiding both its shell and its child sections, the already-initialized fast path must restore the active child section before returning. Refreshing data alone does not make a hidden DOM subtree visible and can produce a blank overlay on the second open. 杩欎唤鏂囨。鏃ㄥ湪璁板綍 Anomalous 鎻掍欢寮�鍙戣繃绋嬩腑鐨勬灦鏋勬紨杩涖�乁X 璁捐鏁欒浠ュ強鏍稿績 Bug 鎺掓煡缁忛獙銆� --- diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 5a27616..db5d247 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2,6 +2,8 @@ This document provides a high-level overview of the Anomalous Model Browser plugin for ComfyUI. It is designed to quickly onboard new AI agents or developers to the project's structure, design philosophy, and critical subsystems. +Workspace lifecycle note: reopening an already initialized Workspace must restore the visible notebook body and reset the hidden recipe body before refreshing data. Hiding the overlay alone is not enough because the next open reuses the existing DOM tree. + ## Current recipe interaction correction (2026-08-03) The recipe detail view keeps Overview, Parameters, and Versions tabs. The Overview contains the model composition blocks; each resolved model name or preview is an explicit entry into the browser model detail view. Model previews are demand-loaded when Overview opens, and returning from model detail restores the recipe detail view. The model browser stores the active grid folder and scroll coordinates before opening detail and restores them when returning to the grid. List-card Append actions await the shared canvas transaction before reporting success or restoring the button state. Export confirmation uses three states (cancel, exclude, include); cancellation must stop the export flow rather than silently becoming an exclusion. @@ -112,7 +114,7 @@ Instead of fragmenting the class scope and losing context, we extracted all UI p * **Detail Panel (`anomalous-detail-panel`)**: Slides out when a specific model is clicked. * **Gallery Viewer (`ui_gallery.js`)**: A fullscreen modal for viewing images. * **Prompt Notes (`ui_notebooks.js`, legacy internal name)**: A specialized editor for composing prompts and drag-dropping LoRA/model nodes. Its shared user-facing surface is **Workspace / 鍒涗綔宸ヤ綔鍙�**, with **Prompt Notes / 鎻愮ず璇嶇瑪璁�** and **Workflow Recipes / 宸ヤ綔娴侀厤鏂�** as its two sections. This presentation rename intentionally leaves notebook routes, storage, and internal property names stable for compatibility. -* **Workflow Recipes (`ui_recipes.js`, `ui_recipe_detail.js`)**: A second section inside the shared Workspace modal, not a separate top-level navigation surface. Recipes save the complete serialized graph and add two summary layers: adapters for common model/LoRA/prompt/sampling semantics, plus bounded generic widget summaries for every node (including third-party nodes). Save captures the serialized graph exactly once before the dialog; that snapshot, not a later live-canvas serialization, is the workflow sent to the API. Schema v3 introduced a canonical SHA-256 workflow fingerprint and explicit model-reference identity records; schema v4 adds optional recipe-owned model-preview snapshot descriptors. The card API stays light; the full graph and history are fetched only after edit, restore, or 鈥淰iew details.鈥� The detail panel owns Overview and Versions tabs. The 'Models' and 'Parameters' tabs were consolidated into the Overview (with Parameters neatly folded into `
`) to reduce cognitive load and avoid state desyncs. The save dialog may pin any safe JSON-serializable widget, restores only pins still present on a canvas update, bind an output cover, and explicitly retain bounded model-preview snapshots. The edit dialog resolves safe primitive values from the full workflow by node ID/widget index before updating the matching serialized slot; bounded summaries are never the edit source. Structural edits are explicitly loaded onto the canvas and saved back through the same update path. Every update archives the previous full recipe locally (bounded to 20 versions). Missing-node preflight also reads authoritative workflow node types. `recipe_parser.js` never mutates the live canvas. +* **Workflow Recipes (`ui_recipes.js`, `ui_recipe_detail.js`)**: A second section inside the shared Workspace modal, not a separate top-level navigation surface. Recipes save the complete serialized graph and add two summary layers: adapters for common model/LoRA/prompt/sampling semantics, plus bounded generic widget summaries for every node (including third-party nodes). Save captures the serialized graph exactly once before the dialog; that snapshot, not a later live-canvas serialization, is the workflow sent to the API. Schema v3 introduced a canonical SHA-256 workflow fingerprint and explicit model-reference identity records; schema v4 adds optional recipe-owned model-preview snapshot descriptors. Schema v5 separates model identity from C-site Official origin metadata (model_name/model_url), ensuring UI rendering prioritizes official names over obfuscated physical filenames. The card API stays light; the full graph and history are fetched only after edit, restore, or 鈥淰iew details.鈥� The detail panel owns Overview and Versions tabs. The 'Models' and 'Parameters' tabs were consolidated into the Overview (with Parameters neatly folded into `
`) to reduce cognitive load and avoid state desyncs. The save dialog may pin any safe JSON-serializable widget, restores only pins still present on a canvas update, bind an output cover, and explicitly retain bounded model-preview snapshots. The edit dialog resolves safe primitive values from the full workflow by node ID/widget index before updating the matching serialized slot; bounded summaries are never the edit source. Structural edits are explicitly loaded onto the canvas and saved back through the same update path. Every update archives the previous full recipe locally (bounded to 20 versions). Missing-node preflight also reads authoritative workflow node types. `recipe_parser.js` never mutates the live canvas. * **Recipe interaction extensions (`recipe_diff.js`, `recipe_actions.js`)**: Recipe cards filter only lightweight name/notes/tags metadata. Version comparison fetches one validated historical JSON and returns bounded semantic changes without instantiating or mutating either graph. Append clones serialized nodes into the live graph with collision-free IDs, transactional link remapping, placement, selection, and rollback. Card and detail actions use a shared busy/restore discipline so a network or canvas failure cannot leave a button permanently disabled or trigger duplicate mutations. Open/Append UI actions share the same exported handlers from `ui_recipe_detail.js`. All Quick Queue functionality was removed to enforce a single execution path through the canvas. * **Recipe detail presentation**: Copy actions use visible temporary success/failure feedback. Name, notes, and tags can be edited inline from the loaded detail view and are persisted through the existing full-recipe update contract, preserving the serialized workflow and history behavior. Workflow fingerprints and model SHA-256 values are advanced information shown only inside collapsed disclosure panels; card and detail surfaces use bounded glass-style cards, responsive grids, and restrained hover transitions. The Overview separates base model and each LoRA into one full-width composition block; sampling values remain in a compact key-value grid. * **Doctor Panel (`ui_doctor.js`)**: Diagnoses model health for individual nodes or the entire workflow. Includes "View Profile" functionality. diff --git a/api/recipes.py b/api/recipes.py index 919a2e6..5a9b22a 100644 --- a/api/recipes.py +++ b/api/recipes.py @@ -183,7 +183,13 @@ def _build_model_references(recipe): saved_value = values[widget_index] if widget_index < len(values) else None if not isinstance(saved_value, str) or not saved_value.strip(): continue - identity, origin = _identity_for_reference(saved_value) + identity_result = _identity_for_reference(saved_value) + if isinstance(identity_result, tuple): + identity, origin = (identity_result + (None,))[:2] + else: + # Keep compatibility with older callers/tests that provide the + # pre-origin helper contract and return identity only. + identity, origin = identity_result, None ref_dict = { "node_id": node.get("id"), "node_type": _node_type(node) or "Unknown", diff --git a/web/modules/ui_notebooks.js b/web/modules/ui_notebooks.js index c2e4da3..2012377 100644 --- a/web/modules/ui_notebooks.js +++ b/web/modules/ui_notebooks.js @@ -45,6 +45,11 @@ export function closeWorkspace() { export async function showNotebooks() { if (this.nbInitialized) { + this.nbPanel.style.display = 'flex'; + if (this.notebookBody) this.notebookBody.style.display = 'flex'; + if (this.recipeView) this.recipeView.style.display = 'none'; + this.notebookNotesTab?.classList.add('active'); + this.notebookRecipesTab?.classList.remove('active'); this.refreshNotebooks(true); return; }