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

@@ -1,5 +1,5 @@
// Recipe Modal Component
import { showToast, copyToClipboard, sendLoraToWorkflow, sendModelPathToWorkflow, openCivitaiByMetadata, stripLoraTags, sendPromptToWorkflow } from '../utils/uiHelpers.js';
import { showToast, copyToClipboard, sendLoraToWorkflow, sendModelPathToWorkflow, openCivitaiByMetadata, stripLoraTags, sendPromptToWorkflow, sendGenParamsToWorkflow } from '../utils/uiHelpers.js';
import { translate } from '../utils/i18nHelpers.js';
import { state } from '../state/index.js';
import { setSessionItem, removeSessionItem, getStorageItem, setStorageItem } from '../utils/storageHelpers.js';
@@ -40,6 +40,16 @@ const GEN_PARAM_NORMALIZATION = {
'Denoising strength': 'denoising_strength',
};
const PARAM_DISPLAY_NAMES = {
steps: 'Steps',
sampler: 'Sampler',
cfg_scale: 'CFG',
seed: 'Seed',
size: 'Size',
clip_skip: 'Clip Skip',
denoising_strength: 'Denoising Strength',
};
class RecipeModal {
constructor() {
this.promptEditorState = {};
@@ -588,10 +598,11 @@ class RecipeModal {
for (const [key, value] of Object.entries(sanitizedGenParams)) {
if (!excludedParams.includes(key) && value !== undefined && value !== null) {
const displayName = PARAM_DISPLAY_NAMES[key] || key;
const paramTag = document.createElement('div');
paramTag.className = 'param-tag';
paramTag.innerHTML = `
<span class="param-name">${key}:</span>
<span class="param-name">${displayName}:</span>
<span class="param-value">${value}</span>
`;
otherParamsElement.appendChild(paramTag);
@@ -1234,6 +1245,19 @@ class RecipeModal {
});
});
}
// Send params to workflow button
const sendParamsBtn = document.getElementById('sendParamsBtn');
if (sendParamsBtn) {
sendParamsBtn.addEventListener('click', () => {
const genParams = this.currentRecipe?.gen_params || {};
if (!genParams || Object.keys(genParams).length === 0) {
showToast('No generation parameters available', {}, 'warning');
return;
}
sendGenParamsToWorkflow(genParams);
});
}
}
/**