fix(ui): allow XML tag for markdown rich input (#6095)

* fix(ui): allow XML tag for rich input

- Introduced utilities for escaping and unescaping non-standard XML/HTML tags to preserve them during markdown processing.
- Updated RichInput and ExpandRichInputDialog components to utilize the new XML tag utilities for handling custom tags.
- Added Jest configuration for the UI package and created tests for the XML tag utilities to ensure functionality.
- Updated package.json to include Jest as a dependency and added a test script.

* address code review comments from Gemini

* allow html tag in markdown editor

* add test case for markdown format

* update dependency in ui
This commit is contained in:
Jocelyn Lin
2026-04-02 09:02:07 -07:00
committed by GitHub
parent c4e689b97a
commit 7df6e95c40
9 changed files with 568 additions and 81 deletions
+5 -2
View File
@@ -247,8 +247,11 @@ export const resolveVariables = async (
// If value is not a string, return as is
if (typeof value !== 'string') return value
// Convert legacy HTML content to markdown, preserving any markdown syntax within
if (/<[a-z][a-z0-9]*[^>]*>/i.test(value)) {
// Convert legacy HTML content to markdown, preserving any markdown syntax within.
// Legacy content from old getHTML() starts with a TipTap block tag (e.g. <p>text</p>).
// Anchor with ^ to avoid matching intentional HTML/XML tags in user prompts
// (e.g. <instruction><div>...</div></instruction>).
if (/^\s*<(?:p|div|h[1-6]|ul|ol|blockquote|pre|table)\b/i.test(value)) {
const turndownService = new TurndownService()
// Disable escaping so markdown characters (e.g. ###, -, *) inside HTML are preserved as-is
turndownService.escape = (str: string) => str
+14
View File
@@ -0,0 +1,14 @@
module.exports = {
roots: ['<rootDir>/src'],
testEnvironment: 'node',
testMatch: ['<rootDir>/src/**/*.test.js'],
testPathIgnorePatterns: ['/node_modules/', '/build/'],
moduleNameMapper: {
'\\.(css|less|scss|sass|svg|png|jpg|jpeg|gif|webp)$': '<rootDir>/src/__mocks__/styleMock.js',
'^@/(.*)$': '<rootDir>/src/$1'
},
transform: {
'^.+\\.jsx?$': 'babel-jest'
},
transformIgnorePatterns: ['/node_modules/']
}
+11
View File
@@ -26,6 +26,7 @@
"@mui/x-tree-view": "^7.25.0",
"@reduxjs/toolkit": "^2.2.7",
"@tabler/icons-react": "^3.30.0",
"@tiptap/core": "^3.20.4",
"@tiptap/extension-code-block-lowlight": "^3.20.4",
"@tiptap/extension-mention": "^3.20.4",
"@tiptap/extension-placeholder": "^3.20.4",
@@ -81,11 +82,20 @@
"dev": "vite",
"start": "vite",
"build": "vite build",
"test": "jest",
"clean": "rimraf build",
"nuke": "rimraf build node_modules .turbo"
},
"babel": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "current"
}
}
],
"@babel/preset-react"
]
},
@@ -108,6 +118,7 @@
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^12.8.3",
"@vitejs/plugin-react": "^4.2.0",
"jest": "^29.7.0",
"pretty-quick": "^3.1.3",
"react-scripts": "^5.0.1",
"rimraf": "^5.0.5",
+1
View File
@@ -0,0 +1 @@
module.exports = {}
@@ -23,15 +23,10 @@ import { common, createLowlight } from 'lowlight'
import { suggestionOptions } from '@/ui-component/input/suggestionOption'
import { getAvailableNodesForVariable } from '@/utils/genericHelper'
import { CustomMention } from '@/utils/customMention'
import { isHtmlContent, escapeXmlTags, unescapeXmlEntities, unescapeXmlTags } from '@/utils/xmlTagUtils'
const lowlight = createLowlight(common)
// Detect if content is legacy HTML (from old getHTML() storage) vs markdown
const isHtmlContent = (content) => {
if (!content || typeof content !== 'string') return false
return /<(?:p|div|span|h[1-6]|ul|ol|li|br|code|pre|blockquote|table|strong|em)\b/i.test(content)
}
// Store
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from '@/store/actions'
@@ -221,7 +216,7 @@ const ExpandRichInputDialog = ({ show, dialogProps, onCancel, onInputHintDialogC
onUpdate: ({ editor }) => {
if (!isSwitchingRef.current) {
try {
setInputValue(editor.getMarkdown())
setInputValue(unescapeXmlTags(editor.getMarkdown()))
} catch {
setInputValue(editor.getHTML())
}
@@ -239,12 +234,13 @@ const ExpandRichInputDialog = ({ show, dialogProps, onCancel, onInputHintDialogC
if (isHtmlContent(inputValue)) {
editor.commands.setContent(inputValue)
try {
setInputValue(editor.getMarkdown())
setInputValue(unescapeXmlTags(editor.getMarkdown()))
} catch {
// keep original value if conversion fails
}
} else {
editor.commands.setContent(inputValue, { contentType: 'markdown' })
editor.commands.setContent(escapeXmlTags(inputValue), { contentType: 'markdown' })
editor.commands.setContent(unescapeXmlEntities(editor.getJSON()))
}
isSwitchingRef.current = false
}
@@ -265,13 +261,17 @@ const ExpandRichInputDialog = ({ show, dialogProps, onCancel, onInputHintDialogC
if (newMode === 'preview' && editor) {
isSwitchingRef.current = true
const contentType = isHtmlContent(inputValue) ? 'html' : 'markdown'
editor.commands.setContent(inputValue, { contentType })
if (isHtmlContent(inputValue)) {
editor.commands.setContent(inputValue, { contentType: 'html' })
} else {
editor.commands.setContent(escapeXmlTags(inputValue), { contentType: 'markdown' })
editor.commands.setContent(unescapeXmlEntities(editor.getJSON()))
}
isSwitchingRef.current = false
setTimeout(() => editor.commands.focus(), 50)
} else if (newMode === 'raw' && editor) {
try {
setInputValue(editor.getMarkdown())
setInputValue(unescapeXmlTags(editor.getMarkdown()))
} catch {
setInputValue(editor.getHTML())
}
@@ -13,15 +13,10 @@ import { common, createLowlight } from 'lowlight'
import { suggestionOptions } from './suggestionOption'
import { getAvailableNodesForVariable } from '@/utils/genericHelper'
import { CustomMention } from '@/utils/customMention'
import { isHtmlContent, escapeXmlTags, unescapeXmlEntities, unescapeXmlTags } from '@/utils/xmlTagUtils'
const lowlight = createLowlight(common)
// Detect if content is legacy HTML (from old getHTML() storage) vs markdown
const isHtmlContent = (content) => {
if (!content || typeof content !== 'string') return false
return /<(?:p|div|span|h[1-6]|ul|ol|li|br|code|pre|blockquote|table|strong|em)\b/i.test(content)
}
// define your extension array
const extensions = (
availableNodesForVariable,
@@ -154,7 +149,7 @@ export const RichInput = ({ inputParam, value, nodes, edges, nodeId, onChange, d
onUpdate: ({ editor }) => {
if (useMarkdown) {
try {
onChange(editor.getMarkdown())
onChange(unescapeXmlTags(editor.getMarkdown()))
} catch {
onChange(editor.getHTML())
}
@@ -173,7 +168,10 @@ export const RichInput = ({ inputParam, value, nodes, edges, nodeId, onChange, d
if (!useMarkdown || isHtmlContent(value)) {
editor.commands.setContent(value)
} else {
editor.commands.setContent(value, { contentType: 'markdown' })
// Step 1: Escape XML tags to entities so marked treats them as text
editor.commands.setContent(escapeXmlTags(value), { contentType: 'markdown' })
// Step 2: Decode entities in the ProseMirror doc for proper display
editor.commands.setContent(unescapeXmlEntities(editor.getJSON()))
}
}
}, [editor]) // eslint-disable-line react-hooks/exhaustive-deps
+107
View File
@@ -0,0 +1,107 @@
/**
* Utilities for preserving XML/HTML tags in prompt text through TipTap's markdown roundtrip.
*
* Problem: When content like `<question>text</question>` is parsed by marked (via @tiptap/markdown),
* the lexer tokenizes tags as HTML tokens. TipTap's parseHTMLToken then calls generateJSON which
* creates DOM elements — unrecognized tags are stripped and only inner text survives.
*
* Solution: Three-step process:
* 1. escapeXmlTags: Convert all tags to HTML entities before markdown parsing
* so marked treats them as text, not HTML tokens.
* 2. unescapeXmlEntities: After TipTap builds the ProseMirror document, walk the JSON tree
* and decode &lt;/&gt; back to </> in text nodes for proper visual display.
* 3. unescapeXmlTags: After getMarkdown(), reverse any remaining entity-escaped tags
* in the serialized output (safety net — typically a no-op).
*/
/**
* Detect if content is legacy HTML from old getHTML() storage vs markdown.
* Legacy content always starts with a block-level tag like <p>.
* Anchored with ^ to avoid matching intentional HTML tags inside user prompts.
*
* @example
* isHtmlContent('<p>some text</p>') // → true (legacy getHTML output)
* isHtmlContent('<instruction>text</instruction>') // → false (user prompt)
*
* @param {string} content - Content to check
* @returns {boolean} True if content looks like legacy HTML
*/
export const isHtmlContent = (content) => {
if (!content || typeof content !== 'string') return false
return /^\s*<(?:p|div|h[1-6]|ul|ol|blockquote|pre|table)\b/i.test(content)
}
/**
* Regex matching opening, closing, and self-closing XML/HTML tags.
* Captures: (1) optional slash, (2) tag name, (3) optional attributes, (4) optional self-close slash
*/
const XML_TAG_REGEX = /<(\/?)([a-zA-Z][a-zA-Z0-9_.-]*)(\s[^>]*)?(\/?)>/g
/**
* Escape all XML/HTML tags to HTML entities so marked doesn't parse them as HTML.
* In prompt editing context, users want tags preserved literally, not rendered.
*
* @example
* escapeXmlTags('<instructions>Be helpful</instructions>')
* // → '&lt;instructions&gt;Be helpful&lt;/instructions&gt;'
*
* escapeXmlTags('<div><question>text</question></div>')
* // → '&lt;div&gt;&lt;question&gt;text&lt;/question&gt;&lt;/div&gt;'
*
* @param {string} text - Raw markdown/text content
* @returns {string} Content with tags escaped to HTML entities
*/
export function escapeXmlTags(text) {
if (!text || typeof text !== 'string') return text
return text.replace(XML_TAG_REGEX, (match, slash, tagName, attrs, selfClose) => {
return `&lt;${slash}${tagName}${attrs || ''}${selfClose}&gt;`
})
}
/**
* Unescape XML tag entities in ProseMirror JSON text nodes.
* Call this after setContent() to fix the visual display in the editor.
* Mutates the JSON in-place and returns it.
*
* @example
* const json = { type: 'doc', content: [
* { type: 'paragraph', content: [{ type: 'text', text: '&lt;question&gt;What?&lt;/question&gt;' }] }
* ]}
* unescapeXmlEntities(json)
* // json.content[0].content[0].text → '<question>What?</question>'
*
* @param {object} json - ProseMirror document JSON from editor.getJSON()
* @returns {object} The same JSON with decoded entities in text nodes
*/
export function unescapeXmlEntities(json) {
if (json.text) {
json.text = unescapeXmlTags(json.text)
}
if (json.content) {
json.content.forEach(unescapeXmlEntities)
}
return json
}
/**
* Unescape all entity-escaped XML/HTML tags after markdown serialization.
*
* @example
* unescapeXmlTags('&lt;question&gt;text&lt;/question&gt;')
* // → '<question>text</question>'
*
* unescapeXmlTags('&lt;div&gt;text&lt;/div&gt;')
* // → '<div>text</div>'
*
* unescapeXmlTags('<question>text</question>')
* // → '<question>text</question>' (raw tags pass through unchanged)
*
* @param {string} text - Markdown output from TipTap
* @returns {string} Content with tags restored to angle brackets
*/
export function unescapeXmlTags(text) {
if (!text || typeof text !== 'string') return text
return text.replace(/&lt;(\/?)([a-zA-Z][a-zA-Z0-9_.-]*)(\s.*?)?(\/?)&gt;/g, (match, slash, tagName, attrs, selfClose) => {
return `<${slash}${tagName}${attrs || ''}${selfClose}>`
})
}
+355
View File
@@ -0,0 +1,355 @@
import { isHtmlContent, escapeXmlTags, unescapeXmlEntities, unescapeXmlTags } from './xmlTagUtils'
describe('xmlTagUtils', () => {
describe('isHtmlContent', () => {
it('should detect legacy getHTML() output starting with <p>', () => {
expect(isHtmlContent('<p>some text</p>')).toBe(true)
})
it('should detect legacy output starting with <div>', () => {
expect(isHtmlContent('<div>content</div>')).toBe(true)
})
it('should detect legacy output with leading whitespace', () => {
expect(isHtmlContent(' <p>text</p>')).toBe(true)
})
it('should NOT detect user prompts starting with custom tags', () => {
expect(isHtmlContent('<instruction>Help me</instruction>')).toBe(false)
})
it('should NOT detect prompts that contain HTML tags mid-content', () => {
expect(isHtmlContent('<instruction><div>Test</div></instruction>')).toBe(false)
})
it('should return false for plain text', () => {
expect(isHtmlContent('just plain text')).toBe(false)
})
it('should return false for empty/null/undefined', () => {
expect(isHtmlContent('')).toBe(false)
expect(isHtmlContent(null)).toBe(false)
expect(isHtmlContent(undefined)).toBe(false)
})
})
describe('escapeXmlTags', () => {
it('should escape opening and closing tags to entities', () => {
expect(escapeXmlTags('<question>text</question>')).toBe('&lt;question&gt;text&lt;/question&gt;')
})
it('should escape self-closing tags', () => {
expect(escapeXmlTags('<my-separator />')).toBe('&lt;my-separator /&gt;')
})
it('should escape tags with attributes', () => {
expect(escapeXmlTags('<context type="user">hello</context>')).toBe('&lt;context type="user"&gt;hello&lt;/context&gt;')
})
it('should escape standard HTML tags too', () => {
expect(escapeXmlTags('<div><p>text</p></div>')).toBe('&lt;div&gt;&lt;p&gt;text&lt;/p&gt;&lt;/div&gt;')
})
it('should escape all tags in mixed content', () => {
const input = '# Heading\n<question>What is {{name}}?</question>\n<p>paragraph</p>'
const expected = '# Heading\n&lt;question&gt;What is {{name}}?&lt;/question&gt;\n&lt;p&gt;paragraph&lt;/p&gt;'
expect(escapeXmlTags(input)).toBe(expected)
})
it('should handle nested tags', () => {
const input = '<outer><inner>text</inner></outer>'
const expected = '&lt;outer&gt;&lt;inner&gt;text&lt;/inner&gt;&lt;/outer&gt;'
expect(escapeXmlTags(input)).toBe(expected)
})
it('should return empty/null/undefined as-is', () => {
expect(escapeXmlTags('')).toBe('')
expect(escapeXmlTags(null)).toBe(null)
expect(escapeXmlTags(undefined)).toBe(undefined)
})
it('should handle text with no tags', () => {
expect(escapeXmlTags('just plain text')).toBe('just plain text')
})
it('should handle tags with dots and hyphens in names', () => {
expect(escapeXmlTags('<my.tag>text</my.tag>')).toBe('&lt;my.tag&gt;text&lt;/my.tag&gt;')
expect(escapeXmlTags('<my-tag>text</my-tag>')).toBe('&lt;my-tag&gt;text&lt;/my-tag&gt;')
})
it('should not double-escape already-escaped content', () => {
const alreadyEscaped = '&lt;question&gt;text&lt;/question&gt;'
expect(escapeXmlTags(alreadyEscaped)).toBe(alreadyEscaped)
})
})
describe('unescapeXmlEntities', () => {
it('should unescape entities in text nodes', () => {
const json = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '&lt;question&gt;What?&lt;/question&gt;' }]
}
]
}
unescapeXmlEntities(json)
expect(json.content[0].content[0].text).toBe('<question>What?</question>')
})
it('should unescape standard HTML tag entities too', () => {
const json = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '&lt;div&gt;content&lt;/div&gt;' }]
}
]
}
unescapeXmlEntities(json)
expect(json.content[0].content[0].text).toBe('<div>content</div>')
})
it('should handle nested content', () => {
const json = {
type: 'doc',
content: [
{
type: 'paragraph',
content: [{ type: 'text', text: '&lt;outer&gt;' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '&lt;inner&gt;text&lt;/inner&gt;' }]
},
{
type: 'paragraph',
content: [{ type: 'text', text: '&lt;/outer&gt;' }]
}
]
}
unescapeXmlEntities(json)
expect(json.content[0].content[0].text).toBe('<outer>')
expect(json.content[1].content[0].text).toBe('<inner>text</inner>')
expect(json.content[2].content[0].text).toBe('</outer>')
})
it('should not modify nodes without entities', () => {
const json = {
type: 'doc',
content: [{ type: 'paragraph', content: [{ type: 'text', text: 'plain text' }] }]
}
unescapeXmlEntities(json)
expect(json.content[0].content[0].text).toBe('plain text')
})
it('should return the same object for chaining', () => {
const json = { type: 'doc', content: [] }
expect(unescapeXmlEntities(json)).toBe(json)
})
})
describe('unescapeXmlTags', () => {
it('should unescape entity-escaped tags', () => {
expect(unescapeXmlTags('&lt;question&gt;text&lt;/question&gt;')).toBe('<question>text</question>')
})
it('should unescape standard HTML tags too', () => {
expect(unescapeXmlTags('&lt;div&gt;text&lt;/div&gt;')).toBe('<div>text</div>')
})
it('should unescape tags with attributes', () => {
expect(unescapeXmlTags('&lt;context type="user"&gt;hello&lt;/context&gt;')).toBe('<context type="user">hello</context>')
})
it('should unescape tags with attributes containing ampersands', () => {
expect(unescapeXmlTags('&lt;datasource url="foo&amp;bar=1"&gt;text&lt;/datasource&gt;')).toBe(
'<datasource url="foo&amp;bar=1">text</datasource>'
)
})
it('should handle mixed content', () => {
const input = '# Heading\n&lt;question&gt;text&lt;/question&gt;\nsome markdown'
const expected = '# Heading\n<question>text</question>\nsome markdown'
expect(unescapeXmlTags(input)).toBe(expected)
})
it('should return empty/null/undefined as-is', () => {
expect(unescapeXmlTags('')).toBe('')
expect(unescapeXmlTags(null)).toBe(null)
expect(unescapeXmlTags(undefined)).toBe(undefined)
})
it('should pass through raw (unescaped) tags unchanged', () => {
expect(unescapeXmlTags('<question>text</question>')).toBe('<question>text</question>')
})
})
describe('roundtrip (escape → unescape)', () => {
const cases = [
'<question>What is the answer?</question>',
'<context type="system">You are helpful</context>',
'<instructions>\n- Step 1\n- Step 2\n</instructions>',
'<outer><inner>nested</inner></outer>',
'# Title\n<question>{{input}}</question>\n**bold** text',
'<my-component />',
'No tags here, just **markdown**',
'<div>standard html preserved</div>',
'<example>This has <strong>standard</strong> HTML inside</example>'
]
cases.forEach((input) => {
it(`should roundtrip: ${input.substring(0, 50)}...`, () => {
const escaped = escapeXmlTags(input)
const restored = unescapeXmlTags(escaped)
expect(restored).toBe(input)
})
})
})
describe('markdown formatting preservation', () => {
it('should preserve heading syntax', () => {
const input = '## My Task\nDo something useful'
expect(escapeXmlTags(input)).toBe(input)
expect(unescapeXmlTags(input)).toBe(input)
})
it('should preserve bold and italic syntax', () => {
const input = 'This is **bold** and *italic* and ***both***'
expect(escapeXmlTags(input)).toBe(input)
expect(unescapeXmlTags(input)).toBe(input)
})
it('should preserve unordered list syntax', () => {
const input = '- Step 1\n- Step 2\n- Step 3'
expect(escapeXmlTags(input)).toBe(input)
expect(unescapeXmlTags(input)).toBe(input)
})
it('should preserve ordered list syntax', () => {
const input = '1. First\n2. Second\n3. Third'
expect(escapeXmlTags(input)).toBe(input)
expect(unescapeXmlTags(input)).toBe(input)
})
it('should preserve code blocks', () => {
const input = '```python\nprint("hello")\n```'
expect(escapeXmlTags(input)).toBe(input)
expect(unescapeXmlTags(input)).toBe(input)
})
it('should preserve inline code', () => {
const input = 'Use `console.log()` for debugging'
expect(escapeXmlTags(input)).toBe(input)
expect(unescapeXmlTags(input)).toBe(input)
})
it('should preserve markdown links [text](url)', () => {
const input = 'See [the docs](https://example.com/path?q=1&r=2) for details'
expect(escapeXmlTags(input)).toBe(input)
expect(unescapeXmlTags(input)).toBe(input)
})
it('should roundtrip HTML <a> links', () => {
const input = 'Visit <a href="https://flowiseai.com">Flowise</a> for docs'
const escaped = escapeXmlTags(input)
expect(escaped).toContain('&lt;a href="https://flowiseai.com"&gt;')
expect(unescapeXmlTags(escaped)).toBe(input)
})
it('should preserve complex pasted markdown with XML tags', () => {
const input =
'## System Prompt\n\n' +
'<instructions>\n' +
'- Be helpful\n' +
'- Be **concise**\n' +
'</instructions>\n\n' +
'See [docs](https://example.com) for more info.\n' +
'Also visit <a href="https://flowiseai.com">Flowise</a>.\n\n' +
'```\ncode block\n```'
const escaped = escapeXmlTags(input)
expect(escaped).not.toBe(input)
const restored = unescapeXmlTags(escaped)
expect(restored).toBe(input)
})
})
/**
* Simulates the full editor save/reload cycle as it happens in RichInput:
*
* LOAD (saved value → editor):
* 1. escapeXmlTags(savedValue) — entities prevent marked from stripping tags
* 2. setContent(escaped, 'markdown') — marked parses entities as text nodes
* 3. unescapeXmlEntities(editor.getJSON()) — fix "&lt;" → "<" in ProseMirror JSON
* 4. setContent(decodedJson) — editor now displays <question> correctly
*
* SAVE (editor → saved value):
* 5. editor.getMarkdown() — serializes text nodes with raw "<"
* 6. unescapeXmlTags(markdown) — safety net for any remaining entities
* 7. onChange(result) — written to flow JSON
*/
describe('full editor save/reload cycle', () => {
function simulateEditorCycle(userInput) {
// --- LOAD ---
// Step 1: escape XML tags to entities
const escaped = escapeXmlTags(userInput)
// Steps 2-3: marked creates text nodes with entities, then unescapeXmlEntities fixes them
const mockJson = {
type: 'doc',
content: [{ type: 'paragraph', content: [{ type: 'text', text: escaped }] }]
}
unescapeXmlEntities(mockJson)
// Step 4: verify editor would display proper angle brackets (no entities)
const editorDisplayText = mockJson.content[0].content[0].text
expect(editorDisplayText).not.toMatch(/&lt;|&gt;/)
// --- SAVE ---
// Step 5: getMarkdown() outputs text node content as-is (no escaping)
const markdownOutput = editorDisplayText
// Step 6: unescape safety net
return unescapeXmlTags(markdownOutput)
}
it('should preserve XML-tagged prompt', () => {
const userInput = '<question>What is the answer?</question>'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
it('should preserve tags with attributes', () => {
const userInput = '<context type="system">You are helpful</context>'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
it('should preserve multiline structured prompt', () => {
const userInput = '<instructions>\n- Step 1\n- Step 2\n</instructions>'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
it('should preserve nested XML tags', () => {
const userInput = '<outer><inner>nested</inner></outer>'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
it('should preserve XML tags mixed with markdown and variables', () => {
const userInput = '# Title\n<question>{{input}}</question>\n**bold** text'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
it('should preserve standard HTML tags too', () => {
const userInput = '<div>content in a div</div>'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
it('should handle mixed custom and standard tags', () => {
const userInput = '<example>This has <strong>bold</strong> HTML inside</example>'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
it('should leave plain markdown unchanged', () => {
const userInput = 'No tags here, just **markdown**'
expect(simulateEditorCycle(userInput)).toBe(userInput)
})
})
})
+57 -59
View File
@@ -812,7 +812,7 @@ importers:
version: 6.11.0
'@google-cloud/logging-winston':
specifier: ^6.0.0
version: 6.0.0([email protected])
version: 6.0.0([email protected])([email protected])
'@keyv/redis':
specifier: ^4.2.0
version: 4.3.3
@@ -986,7 +986,7 @@ importers:
version: 1.2.0
multer-cloud-storage:
specifier: ^4.0.0
version: 4.0.0
version: 4.0.0([email protected])
multer-s3:
specifier: ^3.0.1
version: 3.0.1(@aws-sdk/[email protected])
@@ -1222,6 +1222,9 @@ importers:
'@tabler/icons-react':
specifier: ^3.30.0
version: 3.31.0([email protected])
'@tiptap/core':
specifier: ^3.20.4
version: 3.20.4(@tiptap/[email protected])
'@tiptap/extension-code-block-lowlight':
specifier: ^3.20.4
version: 3.20.4(@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected](@tiptap/[email protected](@tiptap/[email protected]))(@tiptap/[email protected]))(@tiptap/[email protected])([email protected])([email protected])
@@ -1266,10 +1269,10 @@ importers:
version: 16.4.5
flowise-embed:
specifier: latest
version: 3.1.0
version: 3.1.2
flowise-embed-react:
specifier: latest
version: 3.1.1(@types/[email protected])([email protected].0)([email protected]([email protected]))([email protected])([email protected])([email protected])([email protected])
version: 3.1.2(@types/[email protected])([email protected].2)([email protected]([email protected]))([email protected])([email protected])([email protected])([email protected])
flowise-react-json-view:
specifier: '*'
version: 1.21.7(@types/[email protected])([email protected])([email protected]([email protected]))([email protected])
@@ -1391,9 +1394,12 @@ importers:
'@vitejs/plugin-react':
specifier: ^4.2.0
version: 4.2.1([email protected](@types/[email protected])([email protected])([email protected]))
jest:
specifier: ^29.7.0
version: 29.7.0(@types/[email protected])([email protected])([email protected](@swc/[email protected])(@types/[email protected])([email protected]))
pretty-quick:
specifier: ^3.1.3
version: 3.3.1(prettier@3.2.5)
version: 3.3.1(prettier@2.8.8)
react-scripts:
specifier: ^5.0.1
version: 5.0.1(@babel/[email protected](@babel/[email protected]))(@babel/[email protected](@babel/[email protected]))(@swc/[email protected])(@types/[email protected])([email protected])([email protected]([email protected]))([email protected])([email protected])([email protected])([email protected](@swc/[email protected])(@types/[email protected])([email protected]))([email protected])([email protected])([email protected])([email protected])
@@ -2109,6 +2115,7 @@ packages:
'@aws-sdk/[email protected]':
resolution: {integrity: sha512-BGU92StrWF0EJj8jX5EFvRkX9z4/CVIZfON0nWow8gb5ouKwz47o1rO9CP/k2b3F6g134/0XqwXvrUgIWfjJeA==}
engines: {node: '>= 14.0.0'}
deprecated: Please update your @aws-sdk client to a more recent version, such as https://github.com/aws/aws-sdk-js-v3/releases/tag/v3.982.0, if using browser-based WebSocket bidirectional streaming.
'@aws-sdk/[email protected]':
resolution: {integrity: sha512-OH68BRF0rt9nDloq4zsfeHI0G21lj11a66qosaljtEP66PWm7tQ06feKbFkXHT5E1K3QhJW3nVyK8v2fEBY5fg==}
@@ -3578,7 +3585,7 @@ packages:
resolution: {integrity: sha512-C28o4U1T4dPe8avLv1xMQ4MtSE6G4skbVA3VfVZIrpTqklvO+homKB1uFEtNbuZlaKg+Znv8sjmGQUInTH17gA==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-Kx9BCSOLKmqNXEvmViuzsBQJ2VEa/wWwOATNpixOa+suttTV3rDnAUtAIt5ObAUFjXvZakWfFfF/EbxELnGLzQ==, tarball: https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.14.0.tgz}
resolution: {integrity: sha512-Kx9BCSOLKmqNXEvmViuzsBQJ2VEa/wWwOATNpixOa+suttTV3rDnAUtAIt5ObAUFjXvZakWfFfF/EbxELnGLzQ==}
peerDependencies:
'@codemirror/language': ^6.0.0
'@codemirror/state': ^6.0.0
@@ -3601,16 +3608,16 @@ packages:
resolution: {integrity: sha512-VGQfY+FCc285AhWuwjYxQyUQcYurWlxdKYT4bqwr3Twnd5wP5WSeu52t4tvvuWmljT4EmgEgZCqSieokhtY8hg==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==, tarball: https://registry.npmjs.org/@codemirror/lang-json/-/lang-json-6.0.1.tgz}
resolution: {integrity: sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-Hgke565YcO4fd9pe2uLYxnMufHO5rQwRr+AAhFq8ABuhkrjyX8R5p5s+hZUTdV60O0dMRjxKhBLxz8pu/MkUVA==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==, tarball: https://registry.npmjs.org/@codemirror/lang-python/-/lang-python-6.2.1.tgz}
resolution: {integrity: sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==, tarball: https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz}
resolution: {integrity: sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-+5YyicIaaAZKU8K43IQi8TBy6mF6giGeWAH7N96Z5LC30Wm5JMjqxOYIE9mxwMG1NbhT2mA3l9hA4uuKUM3E5g==}
@@ -3619,7 +3626,7 @@ packages:
resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==, tarball: https://registry.npmjs.org/@codemirror/state/-/state-6.4.1.tgz}
resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==}
'@codemirror/[email protected]':
resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==}
@@ -5863,7 +5870,7 @@ packages:
resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==}
'@lezer/[email protected]':
resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==, tarball: https://registry.npmjs.org/@lezer/common/-/common-1.2.1.tgz}
resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==}
'@lezer/[email protected]':
resolution: {integrity: sha512-7JhxupKuMBaWQKjQoLtzhGj83DdnZY9MckEOG5+/iLKNK2ZJqKc6hf6uc0HjwCX7Qlok44jBNqZhHKDhEhZYLA==}
@@ -5878,16 +5885,16 @@ packages:
resolution: {integrity: sha512-5IBr8LIO3xJdJH1e9aj/ZNLE4LSbdsx25wFmGRAZsj2zSmwAYjx26JyU/BYOCpRQlu1jcv1z3vy4NB9+UkfRow==}
'@lezer/[email protected]':
resolution: {integrity: sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==, tarball: https://registry.npmjs.org/@lezer/json/-/json-1.0.2.tgz}
resolution: {integrity: sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==}
'@lezer/[email protected]':
resolution: {integrity: sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==, tarball: https://registry.npmjs.org/@lezer/lr/-/lr-1.4.0.tgz}
resolution: {integrity: sha512-Wst46p51km8gH0ZUmeNrtpRYmdlRHUpN1DQd3GFAyKANi8WVz8c2jHYTf1CVScFaCjQw1iO3ZZdqGDxQPRErTg==}
'@lezer/[email protected]':
resolution: {integrity: sha512-ErbEQ15eowmJUyT095e9NJc3BI9yZ894fjSDtHftD0InkfUBGgnKSU6dvan9jqsZuNHg2+ag/1oyDRxNsENupQ==}
'@lezer/[email protected]':
resolution: {integrity: sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==, tarball: https://registry.npmjs.org/@lezer/python/-/python-1.1.18.tgz}
resolution: {integrity: sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg==}
'@llamaindex/[email protected]':
resolution: {integrity: sha512-8HBSiAZkmX1RvpEM2czEVKqMUCKk7uvMSiDpMGWlEj3MUKBYCh+r8E2TtVhZfU4TunEI7nJRMcVBfXDyFz6Lpw==}
@@ -9251,10 +9258,10 @@ packages:
resolution: {integrity: sha512-rMVl/WrRtN/XtRiLEd/Bnb6TYQqDilZVWi8TC5YpKN6J6uK00zOxlJ7nopm3SwRL8FqzJSybNdMZMnbEKaoYQg==}
'@uiw/[email protected]':
resolution: {integrity: sha512-319zklfinRpKxs9OIowhIt3kDYDe2uTg7Xx5tpYO9lHnU1GiJRQZflXUqxroLqZU1Zfx7pjXtFtVstL3sTuhqw==, tarball: https://registry.npmjs.org/@uiw/codemirror-theme-vscode/-/codemirror-theme-vscode-4.21.24.tgz}
resolution: {integrity: sha512-319zklfinRpKxs9OIowhIt3kDYDe2uTg7Xx5tpYO9lHnU1GiJRQZflXUqxroLqZU1Zfx7pjXtFtVstL3sTuhqw==}
'@uiw/[email protected]':
resolution: {integrity: sha512-InY24KWP8YArDBACWHKFZ6ZU+WCvRHf3ZB2cCVxMVN35P1ANUmRzpAP2ernZQ5OIriL1/A/kXgD0Zg3Y65PNgg==, tarball: https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.21.24.tgz}
resolution: {integrity: sha512-InY24KWP8YArDBACWHKFZ6ZU+WCvRHf3ZB2cCVxMVN35P1ANUmRzpAP2ernZQ5OIriL1/A/kXgD0Zg3Y65PNgg==}
peerDependencies:
'@codemirror/language': '>=6.0.0'
'@codemirror/state': '>=6.0.0'
@@ -9484,6 +9491,7 @@ packages:
'@xmldom/[email protected]':
resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==}
engines: {node: '>=10.0.0'}
deprecated: this version has critical issues, please update to the latest version
'@xtuc/[email protected]':
resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==}
@@ -9865,7 +9873,7 @@ packages:
engines: {node: '>=8'}
[email protected]:
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==, tarball: https://registry.npmjs.org/asap/-/asap-2.0.6.tgz}
resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==}
[email protected]:
resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==}
@@ -10124,7 +10132,7 @@ packages:
resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==}
[email protected]:
resolution: {integrity: sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==, tarball: https://registry.npmjs.org/base16/-/base16-1.0.0.tgz}
resolution: {integrity: sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==}
[email protected]:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
@@ -10144,6 +10152,7 @@ packages:
[email protected]:
resolution: {integrity: sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==}
engines: {node: '>=10.0.0'}
deprecated: Security vulnerability fixed in 5.2.0, please upgrade
[email protected]:
resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==}
@@ -12401,13 +12410,13 @@ packages:
resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==}
[email protected]:
resolution: {integrity: sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==, tarball: https://registry.npmjs.org/fbemitter/-/fbemitter-3.0.0.tgz}
resolution: {integrity: sha512-KWKaceCwKQU0+HPoop6gn4eOHk50bBv/VxjJtGMfwmJt3D29JpN4H4eisCtIPA+a8GVBam+ldMMpMjJUvpDyHw==}
[email protected]:
resolution: {integrity: sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==, tarball: https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz}
resolution: {integrity: sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==}
[email protected]:
resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==, tarball: https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz}
resolution: {integrity: sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==}
[email protected]:
resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==}
@@ -12543,20 +12552,20 @@ packages:
[email protected]:
resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==}
[email protected].1:
resolution: {integrity: sha512-86fL3Z/OLPtTpcL5mgd+pZWaJcOON9L5gOc2NSzMCXeXOXeLtgktfixbeYXZ+22L2pJdD5bDuLByE0GZ04DTcA==}
[email protected].2:
resolution: {integrity: sha512-ugzG31lKAw1hX5oAQ3R8MLff+jFpAYtL55yCUEz4VVN4hgI0c4qsatCWl4WM21xvTJ7SONxxFBzxUawwaG1VoQ==}
peerDependencies:
flowise-embed: '*'
react: 18.x
[email protected].0:
resolution: {integrity: sha512-znZuKTlnEp+YSXzDvCc1x8Z3F4+oKicoLCWokDn3+7DLMSRxXYqfVhr3yVZFfPE8M1akt6szzx57i71Iqksrlg==}
[email protected].2:
resolution: {integrity: sha512-Uo7cqTHUy5Oz93LPy10kiTWpmKL39aJVe6NNKiKSfjajaql2tpS6GBiKv0dTCsOyssbPziCRUCuagOmt4kwYWg==}
[email protected]:
resolution: {integrity: sha512-Er/leiIzJZ691kWqXkjCWv29g0G5qWA4juBOcGZ1P5kBLnkKFxbWc5x8JsSPcHuJQIiGNX/dYEzp2ZrOV3YYMg==}
[email protected]:
resolution: {integrity: sha512-oFjwtSLJkUWk6waLh8heCQ4o9b60FJRA2X8LefaZp5WaJvj/Rr2HILjk+ocf1JkfTcq8jc6t2jfIybg4leWsaQ==, tarball: https://registry.npmjs.org/flowise-react-json-view/-/flowise-react-json-view-1.21.7.tgz}
resolution: {integrity: sha512-oFjwtSLJkUWk6waLh8heCQ4o9b60FJRA2X8LefaZp5WaJvj/Rr2HILjk+ocf1JkfTcq8jc6t2jfIybg4leWsaQ==}
peerDependencies:
react: ^17.0.0 || ^16.3.0 || ^15.5.4
react-dom: ^17.0.0 || ^16.3.0 || ^15.5.4
@@ -12565,7 +12574,7 @@ packages:
resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==}
[email protected]:
resolution: {integrity: sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==, tarball: https://registry.npmjs.org/flux/-/flux-4.0.4.tgz}
resolution: {integrity: sha512-NCj3XlayA2UsapRpM7va6wU1+9rE5FIL7qoMcmxWHRzbp0yujihMBm9BBHZ1MDIk5h5o2Bl6eGiCe8rYELAmYw==}
peerDependencies:
react: ^15.0.2 || ^16.0.0 || ^17.0.0
@@ -14682,7 +14691,7 @@ packages:
resolution: {integrity: sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==}
[email protected]:
resolution: {integrity: sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==, tarball: https://registry.npmjs.org/lodash.curry/-/lodash.curry-4.1.1.tgz}
resolution: {integrity: sha512-/u14pXGviLaweY5JI0IUzgzF2J6Ne8INyzAZjImcryjgkZ+ebruBxy2/JaOOkTqScddcYtakjhSaeemV8lR0tA==}
[email protected]:
resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==}
@@ -14691,7 +14700,7 @@ packages:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
[email protected]:
resolution: {integrity: sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==, tarball: https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz}
resolution: {integrity: sha512-ff3BX/tSioo+XojX4MOsOMhJw0nZoUEF011LX8g8d3gvjVbxd89cCio4BCXronjxcTUIJUoqKEUA+n4CqvvRPw==}
[email protected]:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
@@ -17003,7 +17012,7 @@ packages:
engines: {node: '>=10'}
[email protected]:
resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==, tarball: https://registry.npmjs.org/promise/-/promise-7.3.1.tgz}
resolution: {integrity: sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==}
[email protected]:
resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==}
@@ -17160,7 +17169,7 @@ packages:
deprecated: < 24.15.0 is no longer supported
[email protected]:
resolution: {integrity: sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==, tarball: https://registry.npmjs.org/pure-color/-/pure-color-1.3.0.tgz}
resolution: {integrity: sha512-QFADYnsVoBMw1srW7OVKEYjG+MbIa49s54w1MA1EDY6r2r/sTcKKYqRX1f4GYvnXP7eN/Pe9HFcX+hwzmrXRHA==}
[email protected]:
resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
@@ -17272,7 +17281,7 @@ packages:
engines: {node: '>=14'}
[email protected]:
resolution: {integrity: sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==, tarball: https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz}
resolution: {integrity: sha512-yvh/7CArceR/jNATXOKDlvTnPKPmGZz7zsenQ3jUwLzHkNUR0CvY3yGYJbWJ/nnxsL8Sgmt5cO3/SILVuPO6TQ==}
[email protected]:
resolution: {integrity: sha512-ENNuxG07yO+OuX1ChRje3ieefPRz6yrIpHmebQlaFQgzcAHbUfVeTINpOpoI9bSRSObeYo/OdHsporeToZ7fcg==}
@@ -17346,7 +17355,7 @@ packages:
resolution: {integrity: sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==}
[email protected]:
resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==, tarball: https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz}
resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
[email protected]:
resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==}
@@ -17446,7 +17455,7 @@ packages:
react: '>= 0.14.0'
[email protected]:
resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==, tarball: https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.3.tgz}
resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==}
engines: {node: '>=10'}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -19263,7 +19272,7 @@ packages:
resolution: {integrity: sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==}
[email protected]:
resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==, tarball: https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz}
resolution: {integrity: sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==}
[email protected]:
resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==}
@@ -19469,12 +19478,12 @@ packages:
resolution: {integrity: sha512-K4+koEq4II9FqKKdLyMwfVFiWvTLJsdsIihXCprumjlOwpviO44E4hAhLYBLb6CEVTZh9hXXMTQHIT+Hwv5BPw==}
[email protected]:
resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==, tarball: https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.3.0.tgz}
resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==}
peerDependencies:
react: ^16.8.0 || ^17.0.0 || ^18.0.0
[email protected]:
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==, tarball: https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz}
resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==}
peerDependencies:
'@types/react': '*'
react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -19483,7 +19492,7 @@ packages:
optional: true
[email protected]:
resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==, tarball: https://registry.npmjs.org/use-latest/-/use-latest-1.2.1.tgz}
resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==}
peerDependencies:
'@types/react': '*'
react: ^16.8.0 || ^17.0.0 || ^18.0.0
@@ -20121,7 +20130,7 @@ packages:
engines: {node: '>=4'}
xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz:
resolution: {integrity: sha512-oLDq3jw7AcLqKWH2AhCpVTZl8mf6X2YReP+Neh0SJUzV/BdZYjth94tG5toiMB1PPrYtxOCfaoUCkvtuH+3AJA==, tarball: https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz}
resolution: {tarball: https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz}
version: 0.20.3
engines: {node: '>=0.8'}
hasBin: true
@@ -25493,7 +25502,7 @@ snapshots:
- encoding
- supports-color
'@google-cloud/[email protected]':
'@google-cloud/[email protected]([email protected])':
dependencies:
'@google-cloud/projectify': 4.0.0
'@google-cloud/promisify': 4.1.0
@@ -25508,9 +25517,9 @@ snapshots:
- encoding
- supports-color
'@google-cloud/[email protected]([email protected])':
'@google-cloud/[email protected]([email protected])([email protected])':
dependencies:
'@google-cloud/logging': 11.2.0
'@google-cloud/logging': 11.2.0([email protected])
google-auth-library: 9.15.1([email protected])
lodash.mapvalues: 4.6.0
winston: 3.12.0
@@ -25519,9 +25528,9 @@ snapshots:
- encoding
- supports-color
'@google-cloud/[email protected]':
'@google-cloud/[email protected]([email protected])':
dependencies:
'@google-cloud/common': 5.0.2
'@google-cloud/common': 5.0.2([email protected])
'@google-cloud/paginator': 5.0.2
'@google-cloud/projectify': 4.0.0
'@google-cloud/promisify': 4.1.0
@@ -35683,10 +35692,10 @@ snapshots:
[email protected]: {}
[email protected].1(@types/[email protected])([email protected].0)([email protected]([email protected]))([email protected])([email protected])([email protected])([email protected]):
[email protected].2(@types/[email protected])([email protected].2)([email protected]([email protected]))([email protected])([email protected])([email protected])([email protected]):
dependencies:
'@ladle/react': 2.5.1(@types/[email protected])([email protected]([email protected]))([email protected])([email protected])([email protected])([email protected])
flowise-embed: 3.1.0
flowise-embed: 3.1.2
react: 18.2.0
transitivePeerDependencies:
- '@types/node'
@@ -35700,7 +35709,7 @@ snapshots:
- terser
- typescript
[email protected].0:
[email protected].2:
dependencies:
'@babel/core': 7.24.0
'@microsoft/fetch-event-source': 2.0.1
@@ -39719,7 +39728,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
[email protected]:
[email protected]([email protected]):
dependencies:
'@google-cloud/storage': 7.16.0([email protected])
'@types/express': 5.0.1
@@ -41314,17 +41323,6 @@ snapshots:
prettier: 2.8.8
tslib: 2.6.2
[email protected]([email protected]):
dependencies:
execa: 4.1.0
find-up: 4.1.0
ignore: 5.3.1
mri: 1.2.0
picocolors: 1.0.0
picomatch: 3.0.1
prettier: 3.2.5
tslib: 2.6.2
[email protected]([email protected]):
dependencies:
react: 18.2.0