feat(gallery): expose material snapshot details
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
## 二、当前 MVP 的真实数据链
|
||||
|
||||
```text
|
||||
工作流配方图库中的 PNG
|
||||
主图库或工作流配方图库中的 PNG
|
||||
-> 查看详情
|
||||
-> 后端读取 PNG 内嵌的 UI workflow
|
||||
-> 用户确认或修改默认名称
|
||||
@@ -95,15 +95,16 @@ user/<profile>/workflows/anomalous_materials/
|
||||
|
||||
## 六、MVP 验收标准
|
||||
|
||||
1. 配方图库图片悬浮时能看到“查看详情”。
|
||||
2. 详情为左右栏:左侧图片,右侧参数摘要、名称和保存按钮。
|
||||
3. 保存后,素材库出现一张卡片,插件源码目录没有用户数据。
|
||||
4. “打开完整工作流”使用保存的原始 UI workflow 覆盖当前画布。
|
||||
5. 选中与素材节点同类型的节点后,节点助手能看到该素材中的对应参数块。
|
||||
6. 单节点应用不覆盖 KSampler/KSamplerAdvanced 的种子。
|
||||
7. 源节点的 Hash 证据按目标节点 ID 重映射,随后由模型医生继续处理。
|
||||
8. 只有 API prompt、损坏元数据、越界路径或超大图片不能进入素材库。
|
||||
9. 删除素材时同时删除其私有图片资产,不影响原始输出图。
|
||||
1. 主图库图片悬浮时能看到“查看参数”;配方图库图片悬浮时能看到“查看详情”。
|
||||
2. 主图库原有的单击放大、拖拽、删除和选择模型封面行为不变;选择封面模式不显示素材入口。
|
||||
3. 详情为左右栏:左侧图片,右侧参数摘要、名称和保存按钮。
|
||||
4. 保存后,素材库出现一张卡片,插件源码目录没有用户数据。
|
||||
5. “打开完整工作流”使用保存的原始 UI workflow 覆盖当前画布。
|
||||
6. 选中与素材节点同类型的节点后,节点助手能看到该素材中的对应参数块。
|
||||
7. 单节点应用不覆盖 KSampler/KSamplerAdvanced 的种子。
|
||||
8. 源节点的 Hash 证据按目标节点 ID 重映射,随后由模型医生继续处理。
|
||||
9. 只有 API prompt、损坏元数据、越界路径或超大图片不能进入素材库。
|
||||
10. 删除素材时同时删除其私有图片资产,不影响原始输出图。
|
||||
|
||||
## 七、明确未纳入本次 MVP 的内容
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
- **Optional save-time model verification (保存时可选模型核验)**: Recipe saving now performs a lightweight cached-identity check. Recognized model references missing identity are listed in the save dialog, while full SHA-256 calculation remains explicitly opt-in. This is especially useful for hash-only Model Doctor categories such as VAE and text encoders.
|
||||
- **Model lifecycle consistency (模型生命周期一致性)**: Partial append remaps and merges node-scoped model Hash records, while applying a local model match updates the workflow value, structured model reference, base-model summary, and Hash index together.
|
||||
- **Recipe-scoped model notes (配方模型备注)**: Each model reference can keep a bounded personal note. Package export asks whether to include these notes, and version comparison reports note and identity changes.
|
||||
- **Material Library MVP (统一素材库 MVP)**: Recipe gallery images now expose a two-column parameter detail view and can be saved as one curated bundle containing the original image, exact embedded workflow, model provenance, and reusable node blocks. The Workspace Material Library opens complete snapshots in a new canvas, while Node Assistant filters matching blocks by the selected node type, skips volatile seeds, and hands remapped Hash evidence to Model Doctor.
|
||||
- **Material Library MVP (统一素材库 MVP)**: Main Gallery and Recipe gallery images now expose a non-intrusive two-column parameter detail view and can be saved as one curated bundle containing the original image, exact embedded workflow, model provenance, and reusable node blocks. Main Gallery keeps its existing click, drag, delete, and cover-selection behavior. The Workspace Material Library opens complete snapshots in a new canvas, while Node Assistant filters matching blocks by the selected node type, skips volatile seeds, and hands remapped Hash evidence to Model Doctor.
|
||||
|
||||
### ✨ Interface & Access
|
||||
- **Native Configurable Shortcut (原生可配置快捷键)**: Added `Ctrl + Shift + M` as the default shortcut for opening the browser. The plugin's Interface settings show the currently active binding and open ComfyUI's native key recorder for customization. Conflict detection, overwrite confirmation, removal, reserved-key guidance, and modal guards therefore remain centralized without a separate global keyboard listener.
|
||||
|
||||
@@ -32,10 +32,12 @@ The route family is:
|
||||
## Frontend ownership
|
||||
|
||||
`ui_materials.js` owns the Workspace library, image-inspection/save dialog,
|
||||
full-workflow handoff, and library CRUD presentation. `ui_recipe_detail.js`
|
||||
only supplies the gallery entry point. `ui_doctor.js` owns application to the
|
||||
currently selected node because that mutation already belongs to Node
|
||||
Assistant.
|
||||
full-workflow handoff, and library CRUD presentation. `ui_gallery.js` and
|
||||
`ui_recipe_detail.js` only supply non-invasive gallery entry points. Main
|
||||
Gallery retains click-to-view, drag, delete, and cover-selection behavior; the
|
||||
material action appears only on hover and is hidden during cover selection.
|
||||
`ui_doctor.js` owns application to the currently selected node because that
|
||||
mutation already belongs to Node Assistant.
|
||||
|
||||
A full material workflow is exact and retains its seed. Node-sized reuse is a
|
||||
preset operation and therefore uses the existing transactional parameter
|
||||
|
||||
@@ -51,7 +51,7 @@ export const i18n = {
|
||||
<p><strong>1. 🔄 前置准备 (扫描向导)</strong><br>具体位置:界面左侧底部的 <strong>扫描向导 (🔄)</strong>。<br>这是最重要的前置操作!请先打开扫描向导执行扫描。切记保持网络畅通。部分 C站限制级模型信息需要在设置中填入 API-KEY。扫描完成后,插件的各项功能基本激活。</p>
|
||||
<p><strong>2. 🩺 拯救爆红 (模型医生)</strong><br>具体位置:左侧底部第二个 <strong>听诊器 (🩺)</strong> 按钮。<br>当导入别人使用该插件输出的工作流或者图片时,若模型路径爆红,点击模型医生就能智能识别当前所有节点实现正确路径的替换。</p>
|
||||
<p><strong>3. 🤖 选中交互与参数预设 (节点助手)</strong><br>具体位置:左侧第三个 <strong>机器人 (🤖)</strong> 按钮。<br>在画布上选中节点后,“动作”页可以可视化替换模型,或在兼容的 MODEL + CLIP 链前后插入 LoRA。“参数笔记本”页会按配方分组读取工作流配方保存的同类型节点参数;点击一条记录即可把参数应用到当前选中节点。例如选中 KSampler 后,可一键载入配方中的采样器、调度器、步数、CFG 与降噪等值;种子等每次运行变化的参数会被忽略。</p>
|
||||
<p><strong>4. 🧰 工作流配方、参数笔记本与素材库</strong><br>具体位置:打开 <strong>创作工作台</strong>。<br>配方会保存工作流、封面、标签、备注、模型引用及常用参数。未闭合的局部配方默认追加到当前画布,可独立运行的整体配方会在新画布打开;两者都支持导入/导出配方包。详情页包含概览、参数笔记本、图库和版本:可匹配本地模型、查看与复制完整参数、比较历史出图参数、比较或恢复配方版本。图库图片悬浮后可进入参数详情,把原图、完整工作流和节点参数保存为一个素材快照;素材库可打开完整工作流,节点助手则按当前节点类型筛选并应用其中的参数。参数笔记可从当前画布读取同一骨架的新参数,也可编辑安全控件并保存;“应用到当前工作流”只会在骨架匹配后写入参数。</p>
|
||||
<p><strong>4. 🧰 工作流配方、参数笔记本与素材库</strong><br>具体位置:打开 <strong>创作工作台</strong>。<br>配方会保存工作流、封面、标签、备注、模型引用及常用参数。未闭合的局部配方默认追加到当前画布,可独立运行的整体配方会在新画布打开;两者都支持导入/导出配方包。详情页包含概览、参数笔记本、图库和版本:可匹配本地模型、查看与复制完整参数、比较历史出图参数、比较或恢复配方版本。主图库或配方图库的图片悬浮后可进入参数详情,把原图、完整工作流和节点参数保存为一个素材快照;素材库可打开完整工作流,节点助手则按当前节点类型筛选并应用其中的参数。参数笔记可从当前画布读取同一骨架的新参数,也可编辑安全控件并保存;“应用到当前工作流”只会在骨架匹配后写入参数。</p>
|
||||
<p><strong>5. ⚙️ 个性化配置 (设置面板)</strong><br>具体位置:左侧底部的 <strong>齿轮 (⚙️)</strong> 按钮。<br>可以调节语言、主页面字体大小;进入“模型设置”可选择视频封面始终播放或悬停播放,以及卡片使用流畅缩略图或原始封面。详情页始终保留原图画质。</p>
|
||||
<p><strong>6. 📑 顶部导航与提示词笔记</strong><br>具体位置:右侧顶部的按钮分别为 <strong>模型 (📦)</strong>、<strong>图库 (🖼️)</strong>、<strong>创作工作台 (📑)</strong>、<strong>停靠侧边栏 (◧)</strong>。<br>进入创作工作台的“提示词笔记”,点击新建 <strong>➕</strong>。选择基础模型、主模型和 LoRA 后,可通过 <strong>📝纯文本/粘贴</strong> 填入提示词并进行双语对照、分块、查找替换和标签编辑,最后点击 <strong>🚀 发送到画布</strong> 一键组装节点。</p>
|
||||
<p><strong>7. 📁 文件夹管理 (Folder Manager)</strong><br>具体位置:设置 (⚙️) 面板内的 <strong>📁 文件夹管理</strong>。<br>可以用来隐藏不需要的内置文件夹。隐藏后的文件夹不仅从侧边栏消失,后端的静默扫描和本地读取也会完全跳过,实现真正的“零性能损耗”。并且可以在这里拖拽调整文件夹在侧边栏显示的顺序。</p>
|
||||
@@ -76,6 +76,7 @@ export const i18n = {
|
||||
materialDeleteConfirm: '确定删除这个素材包及其中保存的参考图片吗?',
|
||||
materialDeleteError: '素材删除失败。',
|
||||
materialViewDetails: '查看详情',
|
||||
materialViewParameters: '查看参数',
|
||||
materialImageDetail: '图片参数详情',
|
||||
materialInspecting: '正在读取图片中的工作流与参数…',
|
||||
materialInspectError: '这张图片没有可复用的完整 UI 工作流,暂时不能保存为素材快照。',
|
||||
@@ -851,6 +852,7 @@ export const i18n = {
|
||||
materialDeleteConfirm: 'Delete this material bundle and its saved reference image?',
|
||||
materialDeleteError: 'Could not delete the material.',
|
||||
materialViewDetails: 'View Details',
|
||||
materialViewParameters: 'View Parameters',
|
||||
materialImageDetail: 'Image Parameter Details',
|
||||
materialInspecting: 'Reading the embedded workflow and parameters…',
|
||||
materialInspectError: 'This image has no reusable full UI workflow and cannot be saved as a snapshot yet.',
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { app } from "../../../scripts/app.js";
|
||||
import { translate } from './locales.js';
|
||||
import { showImageMaterialDetail } from './ui_materials.js';
|
||||
|
||||
const t = (key, params) => translate(key, params);
|
||||
|
||||
@@ -86,6 +87,7 @@ export async function loadGalleryImages(page = 1, reset = false) {
|
||||
this.gallerySelectModel = null;
|
||||
const banner = document.getElementById('anomalous-gallery-select-banner');
|
||||
if (banner) banner.style.display = 'none';
|
||||
this.galleryPanel.classList.remove('is-cover-selecting');
|
||||
this.galleryPanel.style.display = 'none';
|
||||
|
||||
await this.loadModels();
|
||||
@@ -208,7 +210,23 @@ export async function loadGalleryImages(page = 1, reset = false) {
|
||||
card.appendChild(overlay);
|
||||
};
|
||||
|
||||
const detailsBtn = document.createElement('button');
|
||||
detailsBtn.className = 'anomalous-gallery-details';
|
||||
detailsBtn.type = 'button';
|
||||
detailsBtn.textContent = `🔎 ${t('materialViewParameters')}`;
|
||||
detailsBtn.title = t('materialViewDetails');
|
||||
detailsBtn.onclick = (event) => {
|
||||
event.stopPropagation();
|
||||
if (this.gallerySelectModel) return;
|
||||
void showImageMaterialDetail(this, {
|
||||
type: 'output',
|
||||
filename: imgData.filename,
|
||||
subfolder: imgData.subfolder || '',
|
||||
}, imgUrl);
|
||||
};
|
||||
|
||||
card.appendChild(img);
|
||||
card.appendChild(detailsBtn);
|
||||
card.appendChild(delBtn);
|
||||
this.galleryGrid.insertBefore(card, this.gallerySentinel);
|
||||
});
|
||||
@@ -451,6 +469,7 @@ export function showGallerySelectMode(model) {
|
||||
this.grid.style.display = 'none';
|
||||
this.detailPanel.style.display = 'none';
|
||||
this.galleryPanel.style.display = 'flex';
|
||||
this.galleryPanel.classList.add('is-cover-selecting');
|
||||
let banner = document.getElementById('anomalous-gallery-select-banner');
|
||||
if (!banner) {
|
||||
banner = document.createElement('div');
|
||||
@@ -487,6 +506,7 @@ export function showGallerySelectMode(model) {
|
||||
cancelSelect.onclick = () => {
|
||||
const tempModel = this.gallerySelectModel;
|
||||
this.gallerySelectModel = null;
|
||||
this.galleryPanel.classList.remove('is-cover-selecting');
|
||||
banner.style.display = 'none';
|
||||
this.galleryPanel.style.display = 'none';
|
||||
if (this.currentDetailModel) {
|
||||
|
||||
@@ -180,7 +180,7 @@ export async function showImageMaterialDetail(owner, sourceImage, imageUrl) {
|
||||
const loading = text(side, 'p', t('materialInspecting'), 'anomalous-material-muted');
|
||||
dialog.append(media, side);
|
||||
overlay.appendChild(dialog);
|
||||
(owner?.nbPanel || document.body).appendChild(overlay);
|
||||
document.body.appendChild(overlay);
|
||||
overlay.addEventListener('click', event => { if (event.target === overlay) overlay.remove(); });
|
||||
|
||||
try {
|
||||
|
||||
@@ -206,6 +206,10 @@ export function createDOM() {
|
||||
galleryBtn.innerHTML = `🖼️ <span class="anomalous-btn-text">${t('gallery') || '图库'}</span>`;
|
||||
galleryBtn.onclick = () => {
|
||||
this.hideAllPanels();
|
||||
this.gallerySelectModel = null;
|
||||
this.galleryPanel.classList.remove('is-cover-selecting');
|
||||
const selectBanner = document.getElementById('anomalous-gallery-select-banner');
|
||||
if (selectBanner) selectBanner.style.display = 'none';
|
||||
container.classList.add('anomalous-sidebar-closed');
|
||||
menuBtn.disabled = true;
|
||||
menuBtn.style.opacity = '0.3';
|
||||
|
||||
+37
-3
@@ -1144,9 +1144,43 @@ html:not(.anomalous-floating-entry-enabled) [data-setting-id="Anomalous.ModelBro
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.anomalous-gallery-card:hover .anomalous-gallery-delete {
|
||||
opacity: 1;
|
||||
}
|
||||
.anomalous-gallery-card:hover .anomalous-gallery-delete {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.anomalous-gallery-details {
|
||||
position: absolute;
|
||||
left: 8px;
|
||||
bottom: 8px;
|
||||
z-index: 2;
|
||||
max-width: calc(100% - 16px);
|
||||
padding: 7px 10px;
|
||||
border: 1px solid rgba(255,255,255,.18);
|
||||
border-radius: 7px;
|
||||
background: rgba(18,20,26,.82);
|
||||
color: #f5f7fb;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transform: translateY(4px);
|
||||
pointer-events: none;
|
||||
backdrop-filter: blur(5px);
|
||||
transition: opacity .16s ease, transform .16s ease, background .16s ease;
|
||||
}
|
||||
|
||||
.anomalous-gallery-card:hover .anomalous-gallery-details,
|
||||
.anomalous-gallery-card:focus-within .anomalous-gallery-details {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.anomalous-gallery-details:hover { background: rgba(31,111,91,.94); }
|
||||
|
||||
#anomalous-gallery-panel.is-cover-selecting .anomalous-gallery-details,
|
||||
#anomalous-gallery-panel.is-cover-selecting .anomalous-gallery-delete {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.anomalous-gallery-delete:hover {
|
||||
background: #ff0000;
|
||||
|
||||
Reference in New Issue
Block a user