mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-05 05:32:02 +00:00
feat: developer profile dashboard, preview asset uploads, and publishing refinements
Add developer profile dialog with editable handle lookup, download history chart (Chart.js with weekly/monthly downsampling), star ratings, review cards, and template list. The handle input allows browsing other developers' profiles via debounced stub service dispatch. Add preview asset upload system for template publishing step 4: thumbnail, before/after comparison, workflow graph, optional video, and gallery of up to 6 images. Uploads are cached in-memory as blob URLs via a module-level singleton composable (useTemplatePreviewAssets). Add reusable TemplateAssetUploadZone component, PreviewField/ PreviewSection sub-components, and templateScreenshotRenderer for generating workflow graph previews from LGraph instances. Internationalize command labels, add workflow actions menu entry for template publishing, and extend marketplace types with CachedAsset, DownloadHistoryEntry, and developer profile models. Bump version to 1.45.0. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -224,6 +224,41 @@ function detectCustomNodes(): string[] {
|
||||
.sort()
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the custom node package ID from a `python_module` string.
|
||||
*
|
||||
* Custom node modules follow the pattern
|
||||
* `custom_nodes.PackageName@version.submodule`, so the package ID is the
|
||||
* second dot-segment with the `@version` suffix stripped.
|
||||
*
|
||||
* @returns The package folder name, or `undefined` when the module does not
|
||||
* match the expected pattern.
|
||||
*/
|
||||
function extractPackageId(pythonModule: string): string | undefined {
|
||||
const segments = pythonModule.split('.')
|
||||
if (segments[0] !== 'custom_nodes' || !segments[1]) return undefined
|
||||
return segments[1].split('@')[0]
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects unique custom node package IDs from the current workflow graph.
|
||||
*/
|
||||
function detectCustomNodePackages(): string[] {
|
||||
if (!app.rootGraph) return []
|
||||
|
||||
const nodeTypes = mapAllNodes(app.rootGraph, (node) => node.type)
|
||||
const packages = new Set<string>()
|
||||
|
||||
for (const type of nodeTypes) {
|
||||
const def = nodeDefStore.nodeDefsByName[type]
|
||||
if (!def || def.nodeSource.type !== NodeSourceType.CustomNodes) continue
|
||||
const pkgId = extractPackageId(def.python_module)
|
||||
if (pkgId) packages.add(pkgId)
|
||||
}
|
||||
|
||||
return [...packages].sort()
|
||||
}
|
||||
|
||||
const detectedCustomNodes = ref<string[]>([])
|
||||
|
||||
onMounted(() => {
|
||||
@@ -233,6 +268,11 @@ onMounted(() => {
|
||||
if (existing.length === 0) {
|
||||
ctx.template.value.requiredNodes = [...detectedCustomNodes.value]
|
||||
}
|
||||
|
||||
const existingPackages = ctx.template.value.requiresCustomNodes ?? []
|
||||
if (existingPackages.length === 0) {
|
||||
ctx.template.value.requiresCustomNodes = detectCustomNodePackages()
|
||||
}
|
||||
})
|
||||
|
||||
const manualNodes = computed(() => {
|
||||
|
||||
Reference in New Issue
Block a user