feat: send gen params to workflow with visual cues

- Add genParamsMapper.js: sampler/scheduler display→internal mapping,
  combined-name parsing, widget matching
- Add sendGenParamsToWorkflow() in uiHelpers.js: resolves sampler,
  fetches registry by send_gen_params marker, sends via update-node-widget
- Add send-params-btn UI in showcase hover panel and recipe modal
- Add flashWidget() in workflow_registry.js: text-color visual cue
  on updated widget values (Vue: inline style + CSS, canvas: property shadow)
- Add silent option to sendWidgetValueToNodes for consolidated toast
- Normalize param display labels (cfg_scale→CFG, etc.) in recipe modal
- Add 33 tests for genParamsMapper; update existing test assertions
This commit is contained in:
Will Miao
2026-06-24 15:39:57 +08:00
parent cd2628a0ee
commit 71a459422f
10 changed files with 952 additions and 24 deletions

View File

@@ -3,7 +3,7 @@
* Media-specific utility functions for showcase components
* (Moved from uiHelpers.js to better organize code)
*/
import { showToast, copyToClipboard, getNSFWLevelName, sendPromptToWorkflow, stripLoraTags } from '../../../utils/uiHelpers.js';
import { showToast, copyToClipboard, getNSFWLevelName, sendPromptToWorkflow, stripLoraTags, sendGenParamsToWorkflow } from '../../../utils/uiHelpers.js';
import { state } from '../../../state/index.js';
import { getModelApiClient } from '../../../api/modelApiFactory.js';
import { NSFW_LEVELS, getMatureBlurThreshold } from '../../../utils/constants.js';
@@ -344,6 +344,48 @@ export function initMetadataPanelHandlers(container) {
});
});
// Handle send params buttons
const paramsBtn = metadataPanel.querySelector('.send-params-btn');
if (paramsBtn) {
paramsBtn.addEventListener('click', async (e) => {
e.stopPropagation();
// Collect gen params from the param-tag elements
const tagsContainer = wrapper.querySelector('.params-tags');
if (!tagsContainer) return;
const paramTags = tagsContainer.querySelectorAll('.param-tag');
const genParams = {};
// Map display labels to genParams keys
const labelToKey = {
'Seed': 'seed',
'Steps': 'steps',
'Sampler': 'sampler',
'CFG': 'cfg_scale',
};
paramTags.forEach(tag => {
const nameEl = tag.querySelector('.param-name');
const valueEl = tag.querySelector('.param-value');
if (!nameEl || !valueEl) return;
const label = nameEl.textContent.replace(':', '').trim();
const key = labelToKey[label];
if (key) {
genParams[key] = valueEl.textContent.trim();
}
});
if (Object.keys(genParams).length === 0) {
showToast('No sendable parameters found', {}, 'warning');
return;
}
await sendGenParamsToWorkflow(genParams);
});
}
// Prevent panel scroll from causing modal scroll
metadataPanel.addEventListener('wheel', (e) => {
const isAtTop = metadataPanel.scrollTop === 0;

View File

@@ -28,14 +28,24 @@ export function generateMetadataPanel(hasParams, hasPrompts, prompt, negativePro
if (hasParams) {
content += `
<div class="params-tags">
${size ? `<div class="param-tag"><span class="param-name">Size:</span><span class="param-value">${size}</span></div>` : ''}
${seed ? `<div class="param-tag"><span class="param-name">Seed:</span><span class="param-value">${seed}</span></div>` : ''}
${model ? `<div class="param-tag"><span class="param-name">Model:</span><span class="param-value">${model}</span></div>` : ''}
${steps ? `<div class="param-tag"><span class="param-name">Steps:</span><span class="param-value">${steps}</span></div>` : ''}
${sampler ? `<div class="param-tag"><span class="param-name">Sampler:</span><span class="param-value">${sampler}</span></div>` : ''}
${cfgScale ? `<div class="param-tag"><span class="param-name">CFG:</span><span class="param-value">${cfgScale}</span></div>` : ''}
${clipSkip ? `<div class="param-tag"><span class="param-name">Clip Skip:</span><span class="param-value">${clipSkip}</span></div>` : ''}
<div class="metadata-row params-row">
<div class="param-header">
<span class="metadata-label">Params:</span>
<div class="param-actions">
<button class="send-params-btn" title="Send Params to Workflow">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
<div class="params-tags">
${size ? `<div class="param-tag"><span class="param-name">Size:</span><span class="param-value">${size}</span></div>` : ''}
${seed ? `<div class="param-tag"><span class="param-name">Seed:</span><span class="param-value">${seed}</span></div>` : ''}
${model ? `<div class="param-tag"><span class="param-name">Model:</span><span class="param-value">${model}</span></div>` : ''}
${steps ? `<div class="param-tag"><span class="param-name">Steps:</span><span class="param-value">${steps}</span></div>` : ''}
${sampler ? `<div class="param-tag"><span class="param-name">Sampler:</span><span class="param-value">${sampler}</span></div>` : ''}
${cfgScale ? `<div class="param-tag"><span class="param-name">CFG:</span><span class="param-value">${cfgScale}</span></div>` : ''}
${clipSkip ? `<div class="param-tag"><span class="param-name">Clip Skip:</span><span class="param-value">${clipSkip}</span></div>` : ''}
</div>
</div>
`;
}