mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 10:42:44 +00:00
Handle HTML fallbacks for node help and skip blueprint docs (#7021)
explicitly prevents subgraphs from making an api call since they don't have docs, this was previously reliant on a non-ok resolution also doesn't try returning anything that has contenttype of text/html to prevent the markdown renderer from crashing ## Summary - short-circuit blueprint/subgraph nodes in help: skip doc fetch and return the node description, avoiding SPA fallback responses - guard node help fetch against HTML/SPA fallbacks using content-type checks; treat them as missing and trigger the existing description fallback - keep base URL logic unchanged for non-blueprint nodes ## Testing - pnpm typecheck - pnpm lint:fix - pnpm test:unit
This commit is contained in:
@@ -7,6 +7,10 @@ class NodeHelpService {
|
|||||||
async fetchNodeHelp(node: ComfyNodeDefImpl, locale: string): Promise<string> {
|
async fetchNodeHelp(node: ComfyNodeDefImpl, locale: string): Promise<string> {
|
||||||
const nodeSource = getNodeSource(node.python_module)
|
const nodeSource = getNodeSource(node.python_module)
|
||||||
|
|
||||||
|
if (nodeSource.type === NodeSourceType.Blueprint) {
|
||||||
|
return node.description || ''
|
||||||
|
}
|
||||||
|
|
||||||
if (nodeSource.type === NodeSourceType.CustomNodes) {
|
if (nodeSource.type === NodeSourceType.CustomNodes) {
|
||||||
return this.fetchCustomNodeHelp(node, locale)
|
return this.fetchCustomNodeHelp(node, locale)
|
||||||
} else {
|
} else {
|
||||||
@@ -19,25 +23,24 @@ class NodeHelpService {
|
|||||||
locale: string
|
locale: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const customNodeName = extractCustomNodeName(node.python_module)
|
const customNodeName = extractCustomNodeName(node.python_module)
|
||||||
|
let lastError: string | undefined
|
||||||
if (!customNodeName) {
|
if (!customNodeName) {
|
||||||
throw new Error('Invalid custom node module')
|
throw new Error('Invalid custom node module')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try locale-specific path first
|
// Try locale-specific path first
|
||||||
const localePath = `/extensions/${customNodeName}/docs/${node.name}/${locale}.md`
|
const localePath = `/extensions/${customNodeName}/docs/${node.name}/${locale}.md`
|
||||||
let res = await fetch(api.fileURL(localePath))
|
const localeDoc = await this.tryFetchMarkdown(localePath)
|
||||||
|
if (localeDoc.text) return localeDoc.text
|
||||||
|
lastError = localeDoc.errorText
|
||||||
|
|
||||||
if (!res.ok) {
|
// Fall back to non-locale path
|
||||||
// Fall back to non-locale path
|
const fallbackPath = `/extensions/${customNodeName}/docs/${node.name}.md`
|
||||||
const fallbackPath = `/extensions/${customNodeName}/docs/${node.name}.md`
|
const fallbackDoc = await this.tryFetchMarkdown(fallbackPath)
|
||||||
res = await fetch(api.fileURL(fallbackPath))
|
if (fallbackDoc.text) return fallbackDoc.text
|
||||||
}
|
lastError = fallbackDoc.errorText ?? lastError
|
||||||
|
|
||||||
if (!res.ok) {
|
throw new Error(lastError ?? 'Help not found')
|
||||||
throw new Error(res.statusText)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res.text()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetchCoreNodeHelp(
|
private async fetchCoreNodeHelp(
|
||||||
@@ -45,13 +48,35 @@ class NodeHelpService {
|
|||||||
locale: string
|
locale: string
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const mdUrl = `/docs/${node.name}/${locale}.md`
|
const mdUrl = `/docs/${node.name}/${locale}.md`
|
||||||
const res = await fetch(api.fileURL(mdUrl))
|
const doc = await this.tryFetchMarkdown(mdUrl)
|
||||||
|
if (!doc.text) {
|
||||||
if (!res.ok) {
|
throw new Error(doc.errorText ?? 'Help not found')
|
||||||
throw new Error(res.statusText)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.text()
|
return doc.text
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch a markdown file and return its text, guarding against HTML/SPA fallbacks.
|
||||||
|
* Returns null when not OK or when the content type indicates HTML.
|
||||||
|
*/
|
||||||
|
private async tryFetchMarkdown(
|
||||||
|
path: string
|
||||||
|
): Promise<{ text: string | null; errorText?: string }> {
|
||||||
|
const res = await fetch(api.fileURL(path))
|
||||||
|
|
||||||
|
if (!res.ok) {
|
||||||
|
return { text: null, errorText: res.statusText }
|
||||||
|
}
|
||||||
|
|
||||||
|
const contentType = res.headers?.get?.('content-type') ?? ''
|
||||||
|
const text = await res.text()
|
||||||
|
|
||||||
|
const isHtmlContentType = contentType.includes('text/html')
|
||||||
|
|
||||||
|
if (isHtmlContentType) return { text: null, errorText: res.statusText }
|
||||||
|
|
||||||
|
return { text }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ export function extractCustomNodeName(
|
|||||||
|
|
||||||
export function getNodeHelpBaseUrl(node: ComfyNodeDefImpl): string {
|
export function getNodeHelpBaseUrl(node: ComfyNodeDefImpl): string {
|
||||||
const nodeSource = getNodeSource(node.python_module)
|
const nodeSource = getNodeSource(node.python_module)
|
||||||
|
if (nodeSource.type === NodeSourceType.Blueprint) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
if (nodeSource.type === NodeSourceType.CustomNodes) {
|
if (nodeSource.type === NodeSourceType.CustomNodes) {
|
||||||
const customNodeName = extractCustomNodeName(node.python_module)
|
const customNodeName = extractCustomNodeName(node.python_module)
|
||||||
if (customNodeName) {
|
if (customNodeName) {
|
||||||
|
|||||||
Reference in New Issue
Block a user