mirror of
https://github.com/open-webui/open-webui.git
synced 2025-12-12 04:15:25 +00:00
UPD: Add Validators & Error Toast for Mermaid & Vega diagrams
### UPD: Feat: Add Validators & Error Toast for Mermaid & Vega diagrams Description: As many time the diagrams generated or entered have syntax errors the diagrams are not rendered due to that errors, but as there isn't any notification is difficult to know what happend. This PR add validator and toast notification when error on Mermaid and Vega/Vega-Lite diagrams, helping the user to fix its. Note: Another possibility of integrating this Graph Visualizer is through its svelte component: https://github.com/vega/svelte-vega/tree/main/packages/svelte-vega
This commit is contained in:
parent
e6cc7db3c1
commit
8538d1b2cb
2 changed files with 37 additions and 49 deletions
|
|
@ -326,12 +326,26 @@
|
||||||
const render = async () => {
|
const render = async () => {
|
||||||
onUpdate(token);
|
onUpdate(token);
|
||||||
if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
|
if (lang === 'mermaid' && (token?.raw ?? '').slice(-4).includes('```')) {
|
||||||
mermaidHtml = await renderMermaidDiagram(code, $i18n);
|
try {
|
||||||
|
mermaidHtml = await renderMermaidDiagram(code);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to render mermaid diagram:', error);
|
||||||
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
||||||
|
toast.error($i18n.t('Failed to render diagram') + `: ${errorMsg}`);
|
||||||
|
mermaidHtml = null;
|
||||||
|
}
|
||||||
} else if (
|
} else if (
|
||||||
(lang === 'vega' || lang === 'vega-lite') &&
|
(lang === 'vega' || lang === 'vega-lite') &&
|
||||||
(token?.raw ?? '').slice(-4).includes('```')
|
(token?.raw ?? '').slice(-4).includes('```')
|
||||||
) {
|
) {
|
||||||
vegaHtml = await renderVegaVisualization(code, $i18n);
|
try {
|
||||||
|
vegaHtml = await renderVegaVisualization(code);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to render Vega visualization:', error);
|
||||||
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
||||||
|
toast.error($i18n.t('Failed to render diagram') + `: ${errorMsg}`);
|
||||||
|
vegaHtml = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1581,56 +1581,30 @@ export const decodeString = (str: string) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const renderMermaidDiagram = async (code: string, i18n?: any) => {
|
export const renderMermaidDiagram = async (code: string) => {
|
||||||
try {
|
const { default: mermaid } = await import('mermaid');
|
||||||
const { default: mermaid } = await import('mermaid');
|
mermaid.initialize({
|
||||||
mermaid.initialize({
|
startOnLoad: false, // Should be false when using render API
|
||||||
startOnLoad: false, // Should be false when using render API
|
theme: document.documentElement.classList.contains('dark') ? 'dark' : 'default',
|
||||||
theme: document.documentElement.classList.contains('dark') ? 'dark' : 'default',
|
securityLevel: 'loose'
|
||||||
securityLevel: 'loose'
|
});
|
||||||
});
|
const parseResult = await mermaid.parse(code, { suppressErrors: false });
|
||||||
const parseResult = await mermaid.parse(code, { suppressErrors: false });
|
if (parseResult) {
|
||||||
if (parseResult) {
|
const { svg } = await mermaid.render(`mermaid-${uuidv4()}`, code);
|
||||||
const { svg } = await mermaid.render(`mermaid-${uuidv4()}`, code);
|
return svg;
|
||||||
return svg;
|
|
||||||
}
|
|
||||||
return '';
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to render mermaid diagram:', error);
|
|
||||||
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
||||||
toast.error(i18n.t('Failed to render diagram') + `: ${errorMsg}`);
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
return '';
|
||||||
};
|
};
|
||||||
|
|
||||||
export const renderVegaVisualization = async (spec: string, i18n?: any) => {
|
export const renderVegaVisualization = async (spec: string, i18n?: any) => {
|
||||||
try {
|
const vega = await import('vega');
|
||||||
const vega = await import('vega');
|
const parsedSpec = JSON.parse(spec);
|
||||||
const parsedSpec = JSON.parse(spec);
|
let vegaSpec = parsedSpec;
|
||||||
if (!parsedSpec.$schema) {
|
if (parsedSpec.$schema && parsedSpec.$schema.includes('vega-lite')) {
|
||||||
const errorMsg = 'Specification missing $schema property';
|
const vegaLite = await import('vega-lite');
|
||||||
toast.error(i18n.t('Failed to render diagram') + `: ${errorMsg}`);
|
vegaSpec = vegaLite.compile(parsedSpec).spec;
|
||||||
throw new Error(errorMsg);
|
|
||||||
}
|
|
||||||
let vegaSpec;
|
|
||||||
if (parsedSpec.$schema.includes('vega-lite')) {
|
|
||||||
const vegaLite = await import('vega-lite');
|
|
||||||
vegaSpec = vegaLite.compile(parsedSpec).spec;
|
|
||||||
} else if (parsedSpec.$schema.includes('vega')) {
|
|
||||||
vegaSpec = parsedSpec;
|
|
||||||
} else {
|
|
||||||
const errorMsg = 'Unknown schema format: ' + parsedSpec.$schema;
|
|
||||||
toast.error(i18n.t('Failed to render diagram') + `: ${errorMsg}`);
|
|
||||||
throw new Error(errorMsg);
|
|
||||||
}
|
|
||||||
const runtime = vega.parse(vegaSpec);
|
|
||||||
const view = new vega.View(runtime, { renderer: 'none' });
|
|
||||||
const svg = await view.toSVG();
|
|
||||||
return svg;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Failed to render Vega visualization:', error);
|
|
||||||
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
||||||
toast.error(i18n.t('Failed to render diagram') + `: ${errorMsg}`);
|
|
||||||
return '';
|
|
||||||
}
|
}
|
||||||
|
const view = new vega.View(vega.parse(vegaSpec), { renderer: 'none' });
|
||||||
|
const svg = await view.toSVG();
|
||||||
|
return svg;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue