Files
Will Miao 720440507c feat: add opt-in workflow library management
Add a Workflows page that manages ComfyUI workflow JSON files as a
first-class library alongside loras/checkpoints/embeddings:

- opt-in via the new 'Workflow Management' settings toggle (default off)
- dedicated workflow folder roots with sidecar/preview support, separate
  from ComfyUI's own workflow storage; 'Send to ComfyUI' loads a workflow
  straight into the graph
- workflow scanner parses the graph document (UI/API format sniffing,
  node classes, model/civitai refs) and persists the analysis in the
  SQLite model cache
- settings UI: workflow folder paths editor in the Library tab and the
  standalone Model Paths page

Fixes from sandbox E2E verification:

- include the workflow scanner in startup initialization so the page no
  longer hangs on 'initializing' when enabled without folders
- add the missing workflows entry to the frontend page-state map (page
  init crashed and the sidebar fell back to the loras tree without it)
- project workflow analysis fields through the scanner cache entry and
  persist them in the model cache (new columns with auto-migration)
- keep symlinked paths intact in the directory picker (abspath instead
  of resolve), so stored library paths match what the user sees on disk

Also rebuilds the vue-widgets bundle to sync it with web/comfyui/utils.js.
2026-10-28 11:45:01 +08:00

48 lines
1.6 KiB
JavaScript

import { LoraApiClient } from './loraApi.js';
import { CheckpointApiClient } from './checkpointApi.js';
import { EmbeddingApiClient } from './embeddingApi.js';
import { OtherApiClient } from './otherApi.js';
import { WorkflowApiClient } from './workflowApi.js';
import { MODEL_TYPES, isValidModelType } from './apiConfig.js';
import { state } from '../state/index.js';
export function createModelApiClient(modelType) {
switch (modelType) {
case MODEL_TYPES.LORA:
return new LoraApiClient(MODEL_TYPES.LORA);
case MODEL_TYPES.CHECKPOINT:
return new CheckpointApiClient(MODEL_TYPES.CHECKPOINT);
case MODEL_TYPES.EMBEDDING:
return new EmbeddingApiClient(MODEL_TYPES.EMBEDDING);
case MODEL_TYPES.OTHER:
return new OtherApiClient(MODEL_TYPES.OTHER);
case MODEL_TYPES.WORKFLOW:
return new WorkflowApiClient(MODEL_TYPES.WORKFLOW);
default:
throw new Error(`Unsupported model type: ${modelType}`);
}
}
let _singletonClients = new Map();
export function getModelApiClient(modelType = null) {
let targetType = modelType;
if (!isValidModelType(targetType)) {
targetType = isValidModelType(state.currentPageType)
? state.currentPageType
: MODEL_TYPES.LORA;
}
if (!_singletonClients.has(targetType)) {
_singletonClients.set(targetType, createModelApiClient(targetType));
}
return _singletonClients.get(targetType);
}
export function resetAndReload(updateFolders = false) {
const client = getModelApiClient();
return client.loadMoreWithVirtualScroll(true, updateFolders);
}