add new utilties - customfunction, setter/getter, replace code editor
This commit is contained in:
parent
1b0b1f13fa
commit
911b4fe7fb
|
|
@ -2,37 +2,7 @@ import { z } from 'zod'
|
||||||
import { CallbackManagerForToolRun } from 'langchain/callbacks'
|
import { CallbackManagerForToolRun } from 'langchain/callbacks'
|
||||||
import { StructuredTool, ToolParams } from 'langchain/tools'
|
import { StructuredTool, ToolParams } from 'langchain/tools'
|
||||||
import { NodeVM } from 'vm2'
|
import { NodeVM } from 'vm2'
|
||||||
|
import { availableDependencies } from '../../../src/utils'
|
||||||
/*
|
|
||||||
* List of dependencies allowed to be import in vm2
|
|
||||||
*/
|
|
||||||
const availableDependencies = [
|
|
||||||
'@dqbd/tiktoken',
|
|
||||||
'@getzep/zep-js',
|
|
||||||
'@huggingface/inference',
|
|
||||||
'@pinecone-database/pinecone',
|
|
||||||
'@supabase/supabase-js',
|
|
||||||
'axios',
|
|
||||||
'cheerio',
|
|
||||||
'chromadb',
|
|
||||||
'cohere-ai',
|
|
||||||
'd3-dsv',
|
|
||||||
'form-data',
|
|
||||||
'graphql',
|
|
||||||
'html-to-text',
|
|
||||||
'langchain',
|
|
||||||
'linkifyjs',
|
|
||||||
'mammoth',
|
|
||||||
'moment',
|
|
||||||
'node-fetch',
|
|
||||||
'pdf-parse',
|
|
||||||
'pdfjs-dist',
|
|
||||||
'playwright',
|
|
||||||
'puppeteer',
|
|
||||||
'srt-parser-2',
|
|
||||||
'typeorm',
|
|
||||||
'weaviate-ts-client'
|
|
||||||
]
|
|
||||||
|
|
||||||
export interface BaseDynamicToolInput extends ToolParams {
|
export interface BaseDynamicToolInput extends ToolParams {
|
||||||
name: string
|
name: string
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
|
||||||
|
import { NodeVM } from 'vm2'
|
||||||
|
import { availableDependencies, handleEscapeCharacters } from '../../../src/utils'
|
||||||
|
|
||||||
|
class CustomFunction_Utilities implements INode {
|
||||||
|
label: string
|
||||||
|
name: string
|
||||||
|
version: number
|
||||||
|
description: string
|
||||||
|
type: string
|
||||||
|
icon: string
|
||||||
|
category: string
|
||||||
|
baseClasses: string[]
|
||||||
|
inputs: INodeParams[]
|
||||||
|
outputs: INodeOutputsValue[]
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.label = 'Custom JS Function'
|
||||||
|
this.name = 'customFunction'
|
||||||
|
this.version = 1.0
|
||||||
|
this.type = 'CustomFunction'
|
||||||
|
this.icon = 'customfunction.svg'
|
||||||
|
this.category = 'Utilities'
|
||||||
|
this.description = `Execute custom javascript function`
|
||||||
|
this.baseClasses = [this.type, 'Utilities']
|
||||||
|
this.inputs = [
|
||||||
|
{
|
||||||
|
label: 'Input Variables',
|
||||||
|
name: 'functionInputVariables',
|
||||||
|
description: 'Input variables can be used in the function with prefix $. For example: $var',
|
||||||
|
type: 'json',
|
||||||
|
optional: true,
|
||||||
|
acceptVariable: true,
|
||||||
|
list: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Function Name',
|
||||||
|
name: 'functionName',
|
||||||
|
type: 'string',
|
||||||
|
optional: true,
|
||||||
|
placeholder: 'My Function'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Javascript Function',
|
||||||
|
name: 'javascriptFunction',
|
||||||
|
type: 'code'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.outputs = [
|
||||||
|
{
|
||||||
|
label: 'Output',
|
||||||
|
name: 'output',
|
||||||
|
baseClasses: ['string', 'number', 'boolean', 'json', 'array']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(nodeData: INodeData, input: string): Promise<any> {
|
||||||
|
const javascriptFunction = nodeData.inputs?.javascriptFunction as string
|
||||||
|
const functionInputVariablesRaw = nodeData.inputs?.functionInputVariables
|
||||||
|
|
||||||
|
let inputVars: ICommonObject = {}
|
||||||
|
if (functionInputVariablesRaw) {
|
||||||
|
try {
|
||||||
|
inputVars =
|
||||||
|
typeof functionInputVariablesRaw === 'object' ? functionInputVariablesRaw : JSON.parse(functionInputVariablesRaw)
|
||||||
|
} catch (exception) {
|
||||||
|
throw new Error("Invalid JSON in the PromptTemplate's promptValues: " + exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sandbox: any = { $input: input }
|
||||||
|
|
||||||
|
if (Object.keys(inputVars).length) {
|
||||||
|
for (const item in inputVars) {
|
||||||
|
sandbox[`$${item}`] = inputVars[item]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultAllowBuiltInDep = [
|
||||||
|
'assert',
|
||||||
|
'buffer',
|
||||||
|
'crypto',
|
||||||
|
'events',
|
||||||
|
'http',
|
||||||
|
'https',
|
||||||
|
'net',
|
||||||
|
'path',
|
||||||
|
'querystring',
|
||||||
|
'timers',
|
||||||
|
'tls',
|
||||||
|
'url',
|
||||||
|
'zlib'
|
||||||
|
]
|
||||||
|
|
||||||
|
const builtinDeps = process.env.TOOL_FUNCTION_BUILTIN_DEP
|
||||||
|
? defaultAllowBuiltInDep.concat(process.env.TOOL_FUNCTION_BUILTIN_DEP.split(','))
|
||||||
|
: defaultAllowBuiltInDep
|
||||||
|
const externalDeps = process.env.TOOL_FUNCTION_EXTERNAL_DEP ? process.env.TOOL_FUNCTION_EXTERNAL_DEP.split(',') : []
|
||||||
|
const deps = availableDependencies.concat(externalDeps)
|
||||||
|
|
||||||
|
const nodeVMOptions = {
|
||||||
|
console: 'inherit',
|
||||||
|
sandbox,
|
||||||
|
require: {
|
||||||
|
external: { modules: deps },
|
||||||
|
builtin: builtinDeps
|
||||||
|
}
|
||||||
|
} as any
|
||||||
|
|
||||||
|
const vm = new NodeVM(nodeVMOptions)
|
||||||
|
try {
|
||||||
|
const response = await vm.run(`module.exports = async function() {${javascriptFunction}}()`, __dirname)
|
||||||
|
if (typeof response === 'string') {
|
||||||
|
return handleEscapeCharacters(response, false)
|
||||||
|
}
|
||||||
|
return response
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { nodeClass: CustomFunction_Utilities }
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-function" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 4m0 2.667a2.667 2.667 0 0 1 2.667 -2.667h10.666a2.667 2.667 0 0 1 2.667 2.667v10.666a2.667 2.667 0 0 1 -2.667 2.667h-10.666a2.667 2.667 0 0 1 -2.667 -2.667z" /><path d="M9 15.5v.25c0 .69 .56 1.25 1.25 1.25c.71 0 1.304 -.538 1.374 -1.244l.752 -7.512a1.381 1.381 0 0 1 1.374 -1.244c.69 0 1.25 .56 1.25 1.25v.25" /><path d="M9 12h6" /></svg>
|
||||||
|
After Width: | Height: | Size: 628 B |
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { ICommonObject, INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
|
||||||
|
|
||||||
|
class GetVariable_Utilities implements INode {
|
||||||
|
label: string
|
||||||
|
name: string
|
||||||
|
version: number
|
||||||
|
description: string
|
||||||
|
type: string
|
||||||
|
icon: string
|
||||||
|
category: string
|
||||||
|
baseClasses: string[]
|
||||||
|
inputs: INodeParams[]
|
||||||
|
outputs: INodeOutputsValue[]
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.label = 'Get Variable'
|
||||||
|
this.name = 'getVariable'
|
||||||
|
this.version = 1.0
|
||||||
|
this.type = 'GetVariable'
|
||||||
|
this.icon = 'getvar.svg'
|
||||||
|
this.category = 'Utilities'
|
||||||
|
this.description = `Get variable that was saved using Set Variable node`
|
||||||
|
this.baseClasses = [this.type, 'Utilities']
|
||||||
|
this.inputs = [
|
||||||
|
{
|
||||||
|
label: 'Variable Name',
|
||||||
|
name: 'variableName',
|
||||||
|
type: 'string',
|
||||||
|
placeholder: 'var1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.outputs = [
|
||||||
|
{
|
||||||
|
label: 'Output',
|
||||||
|
name: 'output',
|
||||||
|
baseClasses: ['string', 'number', 'boolean', 'json', 'array']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(nodeData: INodeData, _: string, options: ICommonObject): Promise<any> {
|
||||||
|
const variableName = nodeData.inputs?.variableName as string
|
||||||
|
const dynamicVars = options.dynamicVariables as Record<string, unknown>
|
||||||
|
|
||||||
|
if (Object.prototype.hasOwnProperty.call(dynamicVars, variableName)) {
|
||||||
|
return dynamicVars[variableName]
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { nodeClass: GetVariable_Utilities }
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-book-download" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 20h-6a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12v5" /><path d="M13 16h-7a2 2 0 0 0 -2 2" /><path d="M15 19l3 3l3 -3" /><path d="M18 22v-9" /></svg>
|
||||||
|
After Width: | Height: | Size: 438 B |
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { INode, INodeData, INodeOutputsValue, INodeParams } from '../../../src/Interface'
|
||||||
|
|
||||||
|
class SetVariable_Utilities implements INode {
|
||||||
|
label: string
|
||||||
|
name: string
|
||||||
|
version: number
|
||||||
|
description: string
|
||||||
|
type: string
|
||||||
|
icon: string
|
||||||
|
category: string
|
||||||
|
baseClasses: string[]
|
||||||
|
inputs: INodeParams[]
|
||||||
|
outputs: INodeOutputsValue[]
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.label = 'Set Variable'
|
||||||
|
this.name = 'setVariable'
|
||||||
|
this.version = 1.0
|
||||||
|
this.type = 'SetVariable'
|
||||||
|
this.icon = 'setvar.svg'
|
||||||
|
this.category = 'Utilities'
|
||||||
|
this.description = `Set variable which can be retrieved at a later stage. Variable is only available during runtime.`
|
||||||
|
this.baseClasses = [this.type, 'Utilities']
|
||||||
|
this.inputs = [
|
||||||
|
{
|
||||||
|
label: 'Input',
|
||||||
|
name: 'input',
|
||||||
|
type: 'string | number | boolean | json | array',
|
||||||
|
optional: true,
|
||||||
|
list: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Variable Name',
|
||||||
|
name: 'variableName',
|
||||||
|
type: 'string',
|
||||||
|
placeholder: 'var1'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
this.outputs = [
|
||||||
|
{
|
||||||
|
label: 'Output',
|
||||||
|
name: 'output',
|
||||||
|
baseClasses: ['string', 'number', 'boolean', 'json', 'array']
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(nodeData: INodeData): Promise<any> {
|
||||||
|
const inputRaw = nodeData.inputs?.input
|
||||||
|
const variableName = nodeData.inputs?.variableName as string
|
||||||
|
|
||||||
|
return { output: inputRaw, dynamicVariables: { [variableName]: inputRaw } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { nodeClass: SetVariable_Utilities }
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-book-upload" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M14 20h-8a2 2 0 0 1 -2 -2v-12a2 2 0 0 1 2 -2h12v5" /><path d="M11 16h-5a2 2 0 0 0 -2 2" /><path d="M15 16l3 -3l3 3" /><path d="M18 13v9" /></svg>
|
||||||
|
After Width: | Height: | Size: 435 B |
|
|
@ -12,6 +12,63 @@ import { AIMessage, HumanMessage } from 'langchain/schema'
|
||||||
|
|
||||||
export const numberOrExpressionRegex = '^(\\d+\\.?\\d*|{{.*}})$' //return true if string consists only numbers OR expression {{}}
|
export const numberOrExpressionRegex = '^(\\d+\\.?\\d*|{{.*}})$' //return true if string consists only numbers OR expression {{}}
|
||||||
export const notEmptyRegex = '(.|\\s)*\\S(.|\\s)*' //return true if string is not empty or blank
|
export const notEmptyRegex = '(.|\\s)*\\S(.|\\s)*' //return true if string is not empty or blank
|
||||||
|
/*
|
||||||
|
* List of dependencies allowed to be import in vm2
|
||||||
|
*/
|
||||||
|
export const availableDependencies = [
|
||||||
|
'@aws-sdk/client-bedrock-runtime',
|
||||||
|
'@aws-sdk/client-dynamodb',
|
||||||
|
'@aws-sdk/client-s3',
|
||||||
|
'@elastic/elasticsearch',
|
||||||
|
'@dqbd/tiktoken',
|
||||||
|
'@getzep/zep-js',
|
||||||
|
'@gomomento/sdk',
|
||||||
|
'@gomomento/sdk-core',
|
||||||
|
'@google-ai/generativelanguage',
|
||||||
|
'@huggingface/inference',
|
||||||
|
'@notionhq/client',
|
||||||
|
'@opensearch-project/opensearch',
|
||||||
|
'@pinecone-database/pinecone',
|
||||||
|
'@qdrant/js-client-rest',
|
||||||
|
'@supabase/supabase-js',
|
||||||
|
'@upstash/redis',
|
||||||
|
'@zilliz/milvus2-sdk-node',
|
||||||
|
'apify-client',
|
||||||
|
'axios',
|
||||||
|
'cheerio',
|
||||||
|
'chromadb',
|
||||||
|
'cohere-ai',
|
||||||
|
'd3-dsv',
|
||||||
|
'faiss-node',
|
||||||
|
'form-data',
|
||||||
|
'google-auth-library',
|
||||||
|
'graphql',
|
||||||
|
'html-to-text',
|
||||||
|
'ioredis',
|
||||||
|
'langchain',
|
||||||
|
'langfuse',
|
||||||
|
'langsmith',
|
||||||
|
'linkifyjs',
|
||||||
|
'llmonitor',
|
||||||
|
'mammoth',
|
||||||
|
'moment',
|
||||||
|
'mongodb',
|
||||||
|
'mysql2',
|
||||||
|
'node-fetch',
|
||||||
|
'node-html-markdown',
|
||||||
|
'notion-to-md',
|
||||||
|
'openai',
|
||||||
|
'pdf-parse',
|
||||||
|
'pdfjs-dist',
|
||||||
|
'pg',
|
||||||
|
'playwright',
|
||||||
|
'puppeteer',
|
||||||
|
'redis',
|
||||||
|
'replicate',
|
||||||
|
'srt-parser-2',
|
||||||
|
'typeorm',
|
||||||
|
'weaviate-ts-client'
|
||||||
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get base classes of components
|
* Get base classes of components
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,28 @@ export class App {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// execute custom function node
|
||||||
|
this.app.post('/api/v1/node-custom-function', async (req: Request, res: Response) => {
|
||||||
|
const body = req.body
|
||||||
|
const nodeData = { inputs: body }
|
||||||
|
if (Object.prototype.hasOwnProperty.call(this.nodesPool.componentNodes, 'customFunction')) {
|
||||||
|
try {
|
||||||
|
const nodeInstanceFilePath = this.nodesPool.componentNodes['customFunction'].filePath as string
|
||||||
|
const nodeModule = await import(nodeInstanceFilePath)
|
||||||
|
const newNodeInstance = new nodeModule.nodeClass()
|
||||||
|
|
||||||
|
const returnOptions: INodeOptionsValue[] = await newNodeInstance.init(nodeData)
|
||||||
|
|
||||||
|
return res.json(returnOptions)
|
||||||
|
} catch (error) {
|
||||||
|
return res.status(500).send(`Error running custom function: ${error}`)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.status(404).send(`Node customFunction not found`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// Chatflows
|
// Chatflows
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -231,6 +231,7 @@ export const buildLangchain = async (
|
||||||
// Create a Queue and add our initial node in it
|
// Create a Queue and add our initial node in it
|
||||||
const nodeQueue = [] as INodeQueue[]
|
const nodeQueue = [] as INodeQueue[]
|
||||||
const exploredNode = {} as IExploredNode
|
const exploredNode = {} as IExploredNode
|
||||||
|
const dynamicVariables = {} as Record<string, unknown>
|
||||||
|
|
||||||
// In the case of infinite loop, only max 3 loops will be executed
|
// In the case of infinite loop, only max 3 loops will be executed
|
||||||
const maxLoop = 3
|
const maxLoop = 3
|
||||||
|
|
@ -267,20 +268,36 @@ export const buildLangchain = async (
|
||||||
appDataSource,
|
appDataSource,
|
||||||
databaseEntities,
|
databaseEntities,
|
||||||
logger,
|
logger,
|
||||||
cachePool
|
cachePool,
|
||||||
|
dynamicVariables
|
||||||
})
|
})
|
||||||
logger.debug(`[server]: Finished upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
logger.debug(`[server]: Finished upserting ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
logger.debug(`[server]: Initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||||
flowNodes[nodeIndex].data.instance = await newNodeInstance.init(reactFlowNodeData, question, {
|
let outputResult = await newNodeInstance.init(reactFlowNodeData, question, {
|
||||||
chatId,
|
chatId,
|
||||||
chatflowid,
|
chatflowid,
|
||||||
appDataSource,
|
appDataSource,
|
||||||
databaseEntities,
|
databaseEntities,
|
||||||
logger,
|
logger,
|
||||||
cachePool
|
cachePool,
|
||||||
|
dynamicVariables
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Save dynamic variables
|
||||||
|
if (reactFlowNode.data.name === 'setVariable') {
|
||||||
|
const dynamicVars = outputResult?.dynamicVariables ?? {}
|
||||||
|
|
||||||
|
for (const variableKey in dynamicVars) {
|
||||||
|
dynamicVariables[variableKey] = dynamicVars[variableKey]
|
||||||
|
}
|
||||||
|
|
||||||
|
outputResult = outputResult?.output
|
||||||
|
}
|
||||||
|
|
||||||
|
flowNodes[nodeIndex].data.instance = outputResult
|
||||||
|
|
||||||
logger.debug(`[server]: Finished initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
logger.debug(`[server]: Finished initializing ${reactFlowNode.data.label} (${reactFlowNode.data.id})`)
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,20 @@
|
||||||
"email": "henryheng@flowiseai.com"
|
"email": "henryheng@flowiseai.com"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@codemirror/lang-javascript": "^6.2.1",
|
||||||
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
|
"@codemirror/view": "^6.22.3",
|
||||||
"@emotion/cache": "^11.4.0",
|
"@emotion/cache": "^11.4.0",
|
||||||
"@emotion/react": "^11.10.6",
|
"@emotion/react": "^11.10.6",
|
||||||
"@emotion/styled": "^11.10.6",
|
"@emotion/styled": "^11.10.6",
|
||||||
"@mui/icons-material": "^5.0.3",
|
"@mui/icons-material": "^5.0.3",
|
||||||
"@mui/material": "^5.11.12",
|
"@mui/lab": "^5.0.0-alpha.156",
|
||||||
|
"@mui/material": "^5.15.0",
|
||||||
"@mui/x-data-grid": "^6.8.0",
|
"@mui/x-data-grid": "^6.8.0",
|
||||||
"@tabler/icons": "^1.39.1",
|
"@tabler/icons": "^1.39.1",
|
||||||
|
"@uiw/codemirror-theme-sublime": "^4.21.21",
|
||||||
|
"@uiw/codemirror-theme-vscode": "^4.21.21",
|
||||||
|
"@uiw/react-codemirror": "^4.21.21",
|
||||||
"clsx": "^1.1.1",
|
"clsx": "^1.1.1",
|
||||||
"flowise-embed": "*",
|
"flowise-embed": "*",
|
||||||
"flowise-embed-react": "*",
|
"flowise-embed-react": "*",
|
||||||
|
|
@ -26,7 +33,6 @@
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moment": "^2.29.3",
|
"moment": "^2.29.3",
|
||||||
"notistack": "^2.0.4",
|
"notistack": "^2.0.4",
|
||||||
"prismjs": "^1.28.0",
|
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.7.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-code-blocks": "^0.0.9-0",
|
"react-code-blocks": "^0.0.9-0",
|
||||||
|
|
@ -39,7 +45,6 @@
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^8.0.5",
|
||||||
"react-router": "~6.3.0",
|
"react-router": "~6.3.0",
|
||||||
"react-router-dom": "~6.3.0",
|
"react-router-dom": "~6.3.0",
|
||||||
"react-simple-code-editor": "^0.11.2",
|
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"reactflow": "^11.5.6",
|
"reactflow": "^11.5.6",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,10 @@ const getAllNodes = () => client.get('/nodes')
|
||||||
|
|
||||||
const getSpecificNode = (name) => client.get(`/nodes/${name}`)
|
const getSpecificNode = (name) => client.get(`/nodes/${name}`)
|
||||||
|
|
||||||
|
const executeCustomFunctionNode = (body) => client.post(`/node-custom-function`, body)
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
getAllNodes,
|
getAllNodes,
|
||||||
getSpecificNode
|
getSpecificNode,
|
||||||
|
executeCustomFunctionNode
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,24 @@ import { createPortal } from 'react-dom'
|
||||||
import { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import { useSelector, useDispatch } from 'react-redux'
|
import { useSelector, useDispatch } from 'react-redux'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
|
import PerfectScrollbar from 'react-perfect-scrollbar'
|
||||||
|
|
||||||
|
// MUI
|
||||||
import { Button, Dialog, DialogActions, DialogContent, Typography } from '@mui/material'
|
import { Button, Dialog, DialogActions, DialogContent, Typography } from '@mui/material'
|
||||||
import { useTheme } from '@mui/material/styles'
|
import { useTheme } from '@mui/material/styles'
|
||||||
import PerfectScrollbar from 'react-perfect-scrollbar'
|
import { LoadingButton } from '@mui/lab'
|
||||||
|
|
||||||
|
// Project Import
|
||||||
import { StyledButton } from 'ui-component/button/StyledButton'
|
import { StyledButton } from 'ui-component/button/StyledButton'
|
||||||
import { DarkCodeEditor } from 'ui-component/editor/DarkCodeEditor'
|
import { CodeEditor } from 'ui-component/editor/CodeEditor'
|
||||||
import { LightCodeEditor } from 'ui-component/editor/LightCodeEditor'
|
|
||||||
|
// Store
|
||||||
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
import { HIDE_CANVAS_DIALOG, SHOW_CANVAS_DIALOG } from 'store/actions'
|
||||||
|
|
||||||
|
// API
|
||||||
|
import nodesApi from 'api/nodes'
|
||||||
|
import useApi from 'hooks/useApi'
|
||||||
|
|
||||||
import './ExpandTextDialog.css'
|
import './ExpandTextDialog.css'
|
||||||
|
|
||||||
const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||||
|
|
@ -18,18 +28,30 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
const customization = useSelector((state) => state.customization)
|
const customization = useSelector((state) => state.customization)
|
||||||
const languageType = 'json'
|
|
||||||
|
|
||||||
const [inputValue, setInputValue] = useState('')
|
const [inputValue, setInputValue] = useState('')
|
||||||
const [inputParam, setInputParam] = useState(null)
|
const [inputParam, setInputParam] = useState(null)
|
||||||
|
const [languageType, setLanguageType] = useState('json')
|
||||||
|
const [loading, setLoading] = useState(false)
|
||||||
|
const [codeExecutedResult, setCodeExecutedResult] = useState('')
|
||||||
|
|
||||||
|
const executeCustomFunctionNodeApi = useApi(nodesApi.executeCustomFunctionNode)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (dialogProps.value) setInputValue(dialogProps.value)
|
if (dialogProps.value) setInputValue(dialogProps.value)
|
||||||
if (dialogProps.inputParam) setInputParam(dialogProps.inputParam)
|
if (dialogProps.inputParam) {
|
||||||
|
setInputParam(dialogProps.inputParam)
|
||||||
|
if (dialogProps.inputParam.type === 'code') {
|
||||||
|
setLanguageType('js')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
setInputValue('')
|
setInputValue('')
|
||||||
|
setLoading(false)
|
||||||
setInputParam(null)
|
setInputParam(null)
|
||||||
|
setLanguageType('json')
|
||||||
|
setCodeExecutedResult('')
|
||||||
}
|
}
|
||||||
}, [dialogProps])
|
}, [dialogProps])
|
||||||
|
|
||||||
|
|
@ -39,11 +61,31 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||||
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
return () => dispatch({ type: HIDE_CANVAS_DIALOG })
|
||||||
}, [show, dispatch])
|
}, [show, dispatch])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setLoading(executeCustomFunctionNodeApi.loading)
|
||||||
|
}, [executeCustomFunctionNodeApi.loading])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (executeCustomFunctionNodeApi.data) {
|
||||||
|
setCodeExecutedResult(executeCustomFunctionNodeApi.data)
|
||||||
|
}
|
||||||
|
}, [executeCustomFunctionNodeApi.data])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (executeCustomFunctionNodeApi.error) {
|
||||||
|
if (typeof executeCustomFunctionNodeApi.error === 'object' && executeCustomFunctionNodeApi.error?.response?.data) {
|
||||||
|
setCodeExecutedResult(executeCustomFunctionNodeApi.error?.response?.data)
|
||||||
|
} else if (typeof executeCustomFunctionNodeApi.error === 'string') {
|
||||||
|
setCodeExecutedResult(executeCustomFunctionNodeApi.error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [executeCustomFunctionNodeApi.error])
|
||||||
|
|
||||||
const component = show ? (
|
const component = show ? (
|
||||||
<Dialog open={show} fullWidth maxWidth='md' aria-labelledby='alert-dialog-title' aria-describedby='alert-dialog-description'>
|
<Dialog open={show} fullWidth maxWidth='md' aria-labelledby='alert-dialog-title' aria-describedby='alert-dialog-description'>
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
<div style={{ display: 'flex', flexDirection: 'row' }}>
|
||||||
{inputParam && inputParam.type === 'string' && (
|
{inputParam && (inputParam.type === 'string' || inputParam.type === 'code') && (
|
||||||
<div style={{ flex: 70 }}>
|
<div style={{ flex: 70 }}>
|
||||||
<Typography sx={{ mb: 2, ml: 1 }} variant='h4'>
|
<Typography sx={{ mb: 2, ml: 1 }} variant='h4'>
|
||||||
{inputParam.label}
|
{inputParam.label}
|
||||||
|
|
@ -54,42 +96,66 @@ const ExpandTextDialog = ({ show, dialogProps, onCancel, onConfirm }) => {
|
||||||
borderColor: theme.palette.grey['500'],
|
borderColor: theme.palette.grey['500'],
|
||||||
borderRadius: '12px',
|
borderRadius: '12px',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
maxHeight: 'calc(100vh - 220px)',
|
maxHeight: languageType === 'js' ? 'calc(100vh - 250px)' : 'calc(100vh - 220px)',
|
||||||
overflowX: 'hidden',
|
overflowX: 'hidden',
|
||||||
backgroundColor: 'white'
|
backgroundColor: 'white'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{customization.isDarkMode ? (
|
<CodeEditor
|
||||||
<DarkCodeEditor
|
disabled={dialogProps.disabled}
|
||||||
disabled={dialogProps.disabled}
|
value={inputValue}
|
||||||
value={inputValue}
|
height={languageType === 'js' ? 'calc(100vh - 250px)' : 'calc(100vh - 220px)'}
|
||||||
onValueChange={(code) => setInputValue(code)}
|
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||||
placeholder={inputParam.placeholder}
|
lang={languageType}
|
||||||
type={languageType}
|
placeholder={inputParam.placeholder}
|
||||||
style={{
|
basicSetup={
|
||||||
fontSize: '0.875rem',
|
languageType === 'json'
|
||||||
minHeight: 'calc(100vh - 220px)',
|
? { lineNumbers: false, foldGutter: false, autocompletion: false, highlightActiveLine: false }
|
||||||
width: '100%'
|
: {}
|
||||||
}}
|
}
|
||||||
/>
|
onValueChange={(code) => setInputValue(code)}
|
||||||
) : (
|
/>
|
||||||
<LightCodeEditor
|
|
||||||
disabled={dialogProps.disabled}
|
|
||||||
value={inputValue}
|
|
||||||
onValueChange={(code) => setInputValue(code)}
|
|
||||||
placeholder={inputParam.placeholder}
|
|
||||||
type={languageType}
|
|
||||||
style={{
|
|
||||||
fontSize: '0.875rem',
|
|
||||||
minHeight: 'calc(100vh - 220px)',
|
|
||||||
width: '100%'
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</PerfectScrollbar>
|
</PerfectScrollbar>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
{languageType === 'js' && (
|
||||||
|
<LoadingButton
|
||||||
|
sx={{
|
||||||
|
mt: 2,
|
||||||
|
'&:hover': {
|
||||||
|
backgroundColor: theme.palette.secondary.main,
|
||||||
|
backgroundImage: `linear-gradient(rgb(0 0 0/10%) 0 0)`
|
||||||
|
},
|
||||||
|
'&:disabled': {
|
||||||
|
backgroundColor: theme.palette.secondary.main,
|
||||||
|
backgroundImage: `linear-gradient(rgb(0 0 0/50%) 0 0)`
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
variant='contained'
|
||||||
|
fullWidth
|
||||||
|
color='secondary'
|
||||||
|
onClick={() => {
|
||||||
|
setLoading(true)
|
||||||
|
executeCustomFunctionNodeApi.request({ javascriptFunction: inputValue })
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Execute
|
||||||
|
</LoadingButton>
|
||||||
|
)}
|
||||||
|
{codeExecutedResult && (
|
||||||
|
<div style={{ marginTop: '15px' }}>
|
||||||
|
<CodeEditor
|
||||||
|
disabled={true}
|
||||||
|
value={codeExecutedResult}
|
||||||
|
height='max-content'
|
||||||
|
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||||
|
lang={'js'}
|
||||||
|
basicSetup={{ lineNumbers: false, foldGutter: false, autocompletion: false, highlightActiveLine: false }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={onCancel}>{dialogProps.cancelButtonName}</Button>
|
<Button onClick={onCancel}>{dialogProps.cancelButtonName}</Button>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
import PropTypes from 'prop-types'
|
||||||
|
import CodeMirror from '@uiw/react-codemirror'
|
||||||
|
import { javascript } from '@codemirror/lang-javascript'
|
||||||
|
import { json } from '@codemirror/lang-json'
|
||||||
|
import { vscodeDark } from '@uiw/codemirror-theme-vscode'
|
||||||
|
import { sublime } from '@uiw/codemirror-theme-sublime'
|
||||||
|
import { EditorView } from '@codemirror/view'
|
||||||
|
|
||||||
|
export const CodeEditor = ({ value, height, theme, lang, placeholder, disabled = false, basicSetup = {}, onValueChange }) => {
|
||||||
|
const customStyle = EditorView.baseTheme({
|
||||||
|
'&': {
|
||||||
|
color: '#191b1f',
|
||||||
|
padding: '10px'
|
||||||
|
},
|
||||||
|
'.cm-placeholder': {
|
||||||
|
color: 'rgba(120, 120, 120, 0.5)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CodeMirror
|
||||||
|
placeholder={placeholder}
|
||||||
|
value={value}
|
||||||
|
height={height ?? 'calc(100vh - 220px)'}
|
||||||
|
theme={theme === 'dark' ? (lang === 'js' ? vscodeDark : sublime) : 'none'}
|
||||||
|
extensions={
|
||||||
|
lang === 'js'
|
||||||
|
? [javascript({ jsx: true }), EditorView.lineWrapping, customStyle]
|
||||||
|
: [json(), EditorView.lineWrapping, customStyle]
|
||||||
|
}
|
||||||
|
onChange={onValueChange}
|
||||||
|
readOnly={disabled}
|
||||||
|
editable={!disabled}
|
||||||
|
basicSetup={basicSetup}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
CodeEditor.propTypes = {
|
||||||
|
value: PropTypes.string,
|
||||||
|
height: PropTypes.string,
|
||||||
|
theme: PropTypes.string,
|
||||||
|
lang: PropTypes.string,
|
||||||
|
placeholder: PropTypes.string,
|
||||||
|
disabled: PropTypes.bool,
|
||||||
|
basicSetup: PropTypes.object,
|
||||||
|
onValueChange: PropTypes.func
|
||||||
|
}
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import Editor from 'react-simple-code-editor'
|
|
||||||
import { highlight, languages } from 'prismjs/components/prism-core'
|
|
||||||
import 'prismjs/components/prism-clike'
|
|
||||||
import 'prismjs/components/prism-javascript'
|
|
||||||
import 'prismjs/components/prism-json'
|
|
||||||
import 'prismjs/components/prism-markup'
|
|
||||||
import './prism-dark.css'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import { useTheme } from '@mui/material/styles'
|
|
||||||
|
|
||||||
export const DarkCodeEditor = ({ value, placeholder, disabled = false, type, style, onValueChange, onMouseUp, onBlur }) => {
|
|
||||||
const theme = useTheme()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Editor
|
|
||||||
disabled={disabled}
|
|
||||||
value={value}
|
|
||||||
placeholder={placeholder}
|
|
||||||
highlight={(code) => highlight(code, type === 'json' ? languages.json : languages.js)}
|
|
||||||
padding={10}
|
|
||||||
onValueChange={onValueChange}
|
|
||||||
onMouseUp={onMouseUp}
|
|
||||||
onBlur={onBlur}
|
|
||||||
tabSize={4}
|
|
||||||
style={{
|
|
||||||
...style,
|
|
||||||
background: theme.palette.codeEditor.main
|
|
||||||
}}
|
|
||||||
textareaClassName='editor__textarea'
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
DarkCodeEditor.propTypes = {
|
|
||||||
value: PropTypes.string,
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
type: PropTypes.string,
|
|
||||||
style: PropTypes.object,
|
|
||||||
onValueChange: PropTypes.func,
|
|
||||||
onMouseUp: PropTypes.func,
|
|
||||||
onBlur: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
import Editor from 'react-simple-code-editor'
|
|
||||||
import { highlight, languages } from 'prismjs/components/prism-core'
|
|
||||||
import 'prismjs/components/prism-clike'
|
|
||||||
import 'prismjs/components/prism-javascript'
|
|
||||||
import 'prismjs/components/prism-json'
|
|
||||||
import 'prismjs/components/prism-markup'
|
|
||||||
import './prism-light.css'
|
|
||||||
import PropTypes from 'prop-types'
|
|
||||||
import { useTheme } from '@mui/material/styles'
|
|
||||||
|
|
||||||
export const LightCodeEditor = ({ value, placeholder, disabled = false, type, style, onValueChange, onMouseUp, onBlur }) => {
|
|
||||||
const theme = useTheme()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Editor
|
|
||||||
disabled={disabled}
|
|
||||||
value={value}
|
|
||||||
placeholder={placeholder}
|
|
||||||
highlight={(code) => highlight(code, type === 'json' ? languages.json : languages.js)}
|
|
||||||
padding={10}
|
|
||||||
onValueChange={onValueChange}
|
|
||||||
onMouseUp={onMouseUp}
|
|
||||||
onBlur={onBlur}
|
|
||||||
tabSize={4}
|
|
||||||
style={{
|
|
||||||
...style,
|
|
||||||
background: theme.palette.card.main
|
|
||||||
}}
|
|
||||||
textareaClassName='editor__textarea'
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
LightCodeEditor.propTypes = {
|
|
||||||
value: PropTypes.string,
|
|
||||||
placeholder: PropTypes.string,
|
|
||||||
disabled: PropTypes.bool,
|
|
||||||
type: PropTypes.string,
|
|
||||||
style: PropTypes.object,
|
|
||||||
onValueChange: PropTypes.func,
|
|
||||||
onMouseUp: PropTypes.func,
|
|
||||||
onBlur: PropTypes.func
|
|
||||||
}
|
|
||||||
|
|
@ -1,275 +0,0 @@
|
||||||
pre[class*='language-'],
|
|
||||||
code[class*='language-'] {
|
|
||||||
color: #d4d4d4;
|
|
||||||
font-size: 13px;
|
|
||||||
text-shadow: none;
|
|
||||||
font-family: Menlo, Monaco, Consolas, 'Andale Mono', 'Ubuntu Mono', 'Courier New', monospace;
|
|
||||||
direction: ltr;
|
|
||||||
text-align: left;
|
|
||||||
white-space: pre;
|
|
||||||
word-spacing: normal;
|
|
||||||
word-break: normal;
|
|
||||||
line-height: 1.5;
|
|
||||||
-moz-tab-size: 4;
|
|
||||||
-o-tab-size: 4;
|
|
||||||
tab-size: 4;
|
|
||||||
-webkit-hyphens: none;
|
|
||||||
-moz-hyphens: none;
|
|
||||||
-ms-hyphens: none;
|
|
||||||
hyphens: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre[class*='language-']::selection,
|
|
||||||
code[class*='language-']::selection,
|
|
||||||
pre[class*='language-'] *::selection,
|
|
||||||
code[class*='language-'] *::selection {
|
|
||||||
text-shadow: none;
|
|
||||||
background: #264f78;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
pre[class*='language-'],
|
|
||||||
code[class*='language-'] {
|
|
||||||
text-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pre[class*='language-'] {
|
|
||||||
padding: 1em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
overflow: auto;
|
|
||||||
background: #1e1e1e;
|
|
||||||
}
|
|
||||||
|
|
||||||
:not(pre) > code[class*='language-'] {
|
|
||||||
padding: 0.1em 0.3em;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
color: #db4c69;
|
|
||||||
background: #1e1e1e;
|
|
||||||
}
|
|
||||||
/*********************************************************
|
|
||||||
* Tokens
|
|
||||||
*/
|
|
||||||
.namespace {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.doctype .token.doctype-tag {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.doctype .token.name {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.comment,
|
|
||||||
.token.prolog {
|
|
||||||
color: #6a9955;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.punctuation,
|
|
||||||
.language-html .language-css .token.punctuation,
|
|
||||||
.language-html .language-javascript .token.punctuation {
|
|
||||||
color: #d4d4d4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.property,
|
|
||||||
.token.tag,
|
|
||||||
.token.boolean,
|
|
||||||
.token.number,
|
|
||||||
.token.constant,
|
|
||||||
.token.symbol,
|
|
||||||
.token.inserted,
|
|
||||||
.token.unit {
|
|
||||||
color: #b5cea8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.selector,
|
|
||||||
.token.attr-name,
|
|
||||||
.token.string,
|
|
||||||
.token.char,
|
|
||||||
.token.builtin,
|
|
||||||
.token.deleted {
|
|
||||||
color: #ce9178;
|
|
||||||
}
|
|
||||||
|
|
||||||
.language-css .token.string.url {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.operator,
|
|
||||||
.token.entity {
|
|
||||||
color: #d4d4d4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.operator.arrow {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule {
|
|
||||||
color: #ce9178;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule .token.rule {
|
|
||||||
color: #c586c0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule .token.url {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule .token.url .token.function {
|
|
||||||
color: #dcdcaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule .token.url .token.punctuation {
|
|
||||||
color: #d4d4d4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.keyword {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.keyword.module,
|
|
||||||
.token.keyword.control-flow {
|
|
||||||
color: #c586c0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.function,
|
|
||||||
.token.function .token.maybe-class-name {
|
|
||||||
color: #dcdcaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.regex {
|
|
||||||
color: #d16969;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.important {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.italic {
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.constant {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.class-name,
|
|
||||||
.token.maybe-class-name {
|
|
||||||
color: #4ec9b0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.console {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.parameter {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.interpolation {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.punctuation.interpolation-punctuation {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.boolean {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.property,
|
|
||||||
.token.variable,
|
|
||||||
.token.imports .token.maybe-class-name,
|
|
||||||
.token.exports .token.maybe-class-name {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.selector {
|
|
||||||
color: #d7ba7d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.escape {
|
|
||||||
color: #d7ba7d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.tag {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.tag .token.punctuation {
|
|
||||||
color: #808080;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.cdata {
|
|
||||||
color: #808080;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.attr-name {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.attr-value,
|
|
||||||
.token.attr-value .token.punctuation {
|
|
||||||
color: #ce9178;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.attr-value .token.punctuation.attr-equals {
|
|
||||||
color: #d4d4d4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.entity {
|
|
||||||
color: #569cd6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.namespace {
|
|
||||||
color: #4ec9b0;
|
|
||||||
}
|
|
||||||
/*********************************************************
|
|
||||||
* Language Specific
|
|
||||||
*/
|
|
||||||
|
|
||||||
pre[class*='language-javascript'],
|
|
||||||
code[class*='language-javascript'],
|
|
||||||
pre[class*='language-jsx'],
|
|
||||||
code[class*='language-jsx'],
|
|
||||||
pre[class*='language-typescript'],
|
|
||||||
code[class*='language-typescript'],
|
|
||||||
pre[class*='language-tsx'],
|
|
||||||
code[class*='language-tsx'] {
|
|
||||||
color: #9cdcfe;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre[class*='language-css'],
|
|
||||||
code[class*='language-css'] {
|
|
||||||
color: #ce9178;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre[class*='language-html'],
|
|
||||||
code[class*='language-html'] {
|
|
||||||
color: #d4d4d4;
|
|
||||||
}
|
|
||||||
|
|
||||||
.language-regex .token.anchor {
|
|
||||||
color: #dcdcaa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.language-html .token.punctuation {
|
|
||||||
color: #808080;
|
|
||||||
}
|
|
||||||
/*********************************************************
|
|
||||||
* Line highlighting
|
|
||||||
*/
|
|
||||||
pre[class*='language-'] > code[class*='language-'] {
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.line-highlight.line-highlight {
|
|
||||||
background: #f7ebc6;
|
|
||||||
box-shadow: inset 5px 0 0 #f7d87c;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
@ -1,207 +0,0 @@
|
||||||
code[class*='language-'],
|
|
||||||
pre[class*='language-'] {
|
|
||||||
text-align: left;
|
|
||||||
white-space: pre;
|
|
||||||
word-spacing: normal;
|
|
||||||
word-break: normal;
|
|
||||||
word-wrap: normal;
|
|
||||||
color: #90a4ae;
|
|
||||||
background: #fafafa;
|
|
||||||
font-family: Roboto Mono, monospace;
|
|
||||||
font-size: 1em;
|
|
||||||
line-height: 1.5em;
|
|
||||||
|
|
||||||
-moz-tab-size: 4;
|
|
||||||
-o-tab-size: 4;
|
|
||||||
tab-size: 4;
|
|
||||||
|
|
||||||
-webkit-hyphens: none;
|
|
||||||
-moz-hyphens: none;
|
|
||||||
-ms-hyphens: none;
|
|
||||||
hyphens: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
code[class*='language-']::-moz-selection,
|
|
||||||
pre[class*='language-']::-moz-selection,
|
|
||||||
code[class*='language-'] ::-moz-selection,
|
|
||||||
pre[class*='language-'] ::-moz-selection {
|
|
||||||
background: #cceae7;
|
|
||||||
color: #263238;
|
|
||||||
}
|
|
||||||
|
|
||||||
code[class*='language-']::selection,
|
|
||||||
pre[class*='language-']::selection,
|
|
||||||
code[class*='language-'] ::selection,
|
|
||||||
pre[class*='language-'] ::selection {
|
|
||||||
background: #cceae7;
|
|
||||||
color: #263238;
|
|
||||||
}
|
|
||||||
|
|
||||||
:not(pre) > code[class*='language-'] {
|
|
||||||
white-space: normal;
|
|
||||||
border-radius: 0.2em;
|
|
||||||
padding: 0.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre[class*='language-'] {
|
|
||||||
overflow: auto;
|
|
||||||
position: relative;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
padding: 1.25em 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.language-css > code,
|
|
||||||
.language-sass > code,
|
|
||||||
.language-scss > code {
|
|
||||||
color: #f76d47;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*='language-'] .namespace {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.atrule {
|
|
||||||
color: #7c4dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.attr-name {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.attr-value {
|
|
||||||
color: #f6a434;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.attribute {
|
|
||||||
color: #f6a434;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.boolean {
|
|
||||||
color: #7c4dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.builtin {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.cdata {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.char {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.class {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.class-name {
|
|
||||||
color: #6182b8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.comment {
|
|
||||||
color: #aabfc9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.constant {
|
|
||||||
color: #7c4dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.deleted {
|
|
||||||
color: #e53935;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.doctype {
|
|
||||||
color: #aabfc9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.entity {
|
|
||||||
color: #e53935;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.function {
|
|
||||||
color: #7c4dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.hexcode {
|
|
||||||
color: #f76d47;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.id {
|
|
||||||
color: #7c4dff;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.important {
|
|
||||||
color: #7c4dff;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.inserted {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.keyword {
|
|
||||||
color: #7c4dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.number {
|
|
||||||
color: #f76d47;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.operator {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.prolog {
|
|
||||||
color: #aabfc9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.property {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.pseudo-class {
|
|
||||||
color: #f6a434;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.pseudo-element {
|
|
||||||
color: #f6a434;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.punctuation {
|
|
||||||
color: #39adb5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.regex {
|
|
||||||
color: #6182b8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.selector {
|
|
||||||
color: #e53935;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.string {
|
|
||||||
color: #f6a434;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.symbol {
|
|
||||||
color: #7c4dff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.tag {
|
|
||||||
color: #e53935;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.unit {
|
|
||||||
color: #f76d47;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.url {
|
|
||||||
color: #e53935;
|
|
||||||
}
|
|
||||||
|
|
||||||
.token.variable {
|
|
||||||
color: #e53935;
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +1,10 @@
|
||||||
import { useState, useEffect, useRef } from 'react'
|
import { useState, useEffect, useRef } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { FormControl, OutlinedInput, Popover } from '@mui/material'
|
import { FormControl, OutlinedInput, Popover } from '@mui/material'
|
||||||
import ExpandTextDialog from 'ui-component/dialog/ExpandTextDialog'
|
|
||||||
import SelectVariable from 'ui-component/json/SelectVariable'
|
import SelectVariable from 'ui-component/json/SelectVariable'
|
||||||
import { getAvailableNodesForVariable } from 'utils/genericHelper'
|
import { getAvailableNodesForVariable } from 'utils/genericHelper'
|
||||||
|
|
||||||
export const Input = ({
|
export const Input = ({ inputParam, value, nodes, edges, nodeId, onChange, disabled = false }) => {
|
||||||
inputParam,
|
|
||||||
value,
|
|
||||||
nodes,
|
|
||||||
edges,
|
|
||||||
nodeId,
|
|
||||||
onChange,
|
|
||||||
disabled = false,
|
|
||||||
showDialog,
|
|
||||||
dialogProps,
|
|
||||||
onDialogCancel,
|
|
||||||
onDialogConfirm
|
|
||||||
}) => {
|
|
||||||
const [myValue, setMyValue] = useState(value ?? '')
|
const [myValue, setMyValue] = useState(value ?? '')
|
||||||
const [anchorEl, setAnchorEl] = useState(null)
|
const [anchorEl, setAnchorEl] = useState(null)
|
||||||
const [availableNodesForVariable, setAvailableNodesForVariable] = useState([])
|
const [availableNodesForVariable, setAvailableNodesForVariable] = useState([])
|
||||||
|
|
@ -86,17 +73,6 @@ export const Input = ({
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
{showDialog && (
|
|
||||||
<ExpandTextDialog
|
|
||||||
show={showDialog}
|
|
||||||
dialogProps={dialogProps}
|
|
||||||
onCancel={onDialogCancel}
|
|
||||||
onConfirm={(newValue, inputParamName) => {
|
|
||||||
setMyValue(newValue)
|
|
||||||
onDialogConfirm(newValue, inputParamName)
|
|
||||||
}}
|
|
||||||
></ExpandTextDialog>
|
|
||||||
)}
|
|
||||||
<div ref={ref}></div>
|
<div ref={ref}></div>
|
||||||
{inputParam?.acceptVariable && (
|
{inputParam?.acceptVariable && (
|
||||||
<Popover
|
<Popover
|
||||||
|
|
@ -131,11 +107,7 @@ Input.propTypes = {
|
||||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
showDialog: PropTypes.bool,
|
|
||||||
dialogProps: PropTypes.object,
|
|
||||||
nodes: PropTypes.array,
|
nodes: PropTypes.array,
|
||||||
edges: PropTypes.array,
|
edges: PropTypes.array,
|
||||||
nodeId: PropTypes.string,
|
nodeId: PropTypes.string
|
||||||
onDialogCancel: PropTypes.func,
|
|
||||||
onDialogConfirm: PropTypes.func
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,12 @@ const SelectVariable = ({ availableNodesForVariable, disabled = false, onSelectA
|
||||||
</ListItemAvatar>
|
</ListItemAvatar>
|
||||||
<ListItemText
|
<ListItemText
|
||||||
sx={{ ml: 1 }}
|
sx={{ ml: 1 }}
|
||||||
primary={node.data.inputs.chainName ? node.data.inputs.chainName : node.data.id}
|
primary={
|
||||||
|
node.data.inputs.chainName ??
|
||||||
|
node.data.inputs.functionName ??
|
||||||
|
node.data.inputs.variableName ??
|
||||||
|
node.data.id
|
||||||
|
}
|
||||||
secondary={`${selectedOutputAnchor?.label ?? 'output'} from ${node.data.label}`}
|
secondary={`${selectedOutputAnchor?.label ?? 'output'} from ${node.data.label}`}
|
||||||
/>
|
/>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,11 @@ import { flowContext } from 'store/context/ReactFlowContext'
|
||||||
import { isValidConnection } from 'utils/genericHelper'
|
import { isValidConnection } from 'utils/genericHelper'
|
||||||
import { JsonEditorInput } from 'ui-component/json/JsonEditor'
|
import { JsonEditorInput } from 'ui-component/json/JsonEditor'
|
||||||
import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
||||||
|
import { CodeEditor } from 'ui-component/editor/CodeEditor'
|
||||||
|
|
||||||
import ToolDialog from 'views/tools/ToolDialog'
|
import ToolDialog from 'views/tools/ToolDialog'
|
||||||
import AssistantDialog from 'views/assistants/AssistantDialog'
|
import AssistantDialog from 'views/assistants/AssistantDialog'
|
||||||
|
import ExpandTextDialog from 'ui-component/dialog/ExpandTextDialog'
|
||||||
import FormatPromptValuesDialog from 'ui-component/dialog/FormatPromptValuesDialog'
|
import FormatPromptValuesDialog from 'ui-component/dialog/FormatPromptValuesDialog'
|
||||||
import CredentialInputHandler from './CredentialInputHandler'
|
import CredentialInputHandler from './CredentialInputHandler'
|
||||||
|
|
||||||
|
|
@ -83,7 +86,7 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const onFormatPromptValuesClicked = (value, inputParam) => {
|
const onEditJSONClicked = (value, inputParam) => {
|
||||||
// Preset values if the field is format prompt values
|
// Preset values if the field is format prompt values
|
||||||
let inputValue = value
|
let inputValue = value
|
||||||
if (inputParam.name === 'promptValues' && !value) {
|
if (inputParam.name === 'promptValues' && !value) {
|
||||||
|
|
@ -255,7 +258,7 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||||
{inputParam.description && <TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />}
|
{inputParam.description && <TooltipWithParser style={{ marginLeft: 10 }} title={inputParam.description} />}
|
||||||
</Typography>
|
</Typography>
|
||||||
<div style={{ flexGrow: 1 }}></div>
|
<div style={{ flexGrow: 1 }}></div>
|
||||||
{inputParam.type === 'string' && inputParam.rows && (
|
{((inputParam.type === 'string' && inputParam.rows) || inputParam.type === 'code') && (
|
||||||
<IconButton
|
<IconButton
|
||||||
size='small'
|
size='small'
|
||||||
sx={{
|
sx={{
|
||||||
|
|
@ -324,6 +327,23 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||||
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)}
|
onChange={(newValue) => (data.inputs[inputParam.name] = newValue)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{inputParam.type === 'code' && (
|
||||||
|
<>
|
||||||
|
<div style={{ height: '5px' }}></div>
|
||||||
|
<div style={{ height: '200px' }}>
|
||||||
|
<CodeEditor
|
||||||
|
disabled={disabled}
|
||||||
|
value={data.inputs[inputParam.name] ?? inputParam.default ?? ''}
|
||||||
|
height='200px'
|
||||||
|
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||||
|
lang={'js'}
|
||||||
|
placeholder={inputParam.placeholder}
|
||||||
|
onValueChange={(code) => (data.inputs[inputParam.name] = code)}
|
||||||
|
basicSetup={{ highlightActiveLine: false, highlightActiveLineGutter: false }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && (
|
{(inputParam.type === 'string' || inputParam.type === 'password' || inputParam.type === 'number') && (
|
||||||
<Input
|
<Input
|
||||||
key={data.inputs[inputParam.name]}
|
key={data.inputs[inputParam.name]}
|
||||||
|
|
@ -334,10 +354,6 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||||
nodes={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getNodes() : []}
|
nodes={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getNodes() : []}
|
||||||
edges={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getEdges() : []}
|
edges={inputParam?.acceptVariable && reactFlowInstance ? reactFlowInstance.getEdges() : []}
|
||||||
nodeId={data.id}
|
nodeId={data.id}
|
||||||
showDialog={showExpandDialog}
|
|
||||||
dialogProps={expandDialogProps}
|
|
||||||
onDialogCancel={() => setShowExpandDialog(false)}
|
|
||||||
onDialogConfirm={(newValue, inputParamName) => onExpandDialogSave(newValue, inputParamName)}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{inputParam.type === 'json' && (
|
{inputParam.type === 'json' && (
|
||||||
|
|
@ -353,11 +369,11 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||||
{inputParam?.acceptVariable && (
|
{inputParam?.acceptVariable && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
sx={{ borderRadius: 25, width: '100%', mb: 2, mt: 2 }}
|
sx={{ borderRadius: 25, width: '100%', mb: 0, mt: 2 }}
|
||||||
variant='outlined'
|
variant='outlined'
|
||||||
onClick={() => onFormatPromptValuesClicked(data.inputs[inputParam.name] ?? '', inputParam)}
|
onClick={() => onEditJSONClicked(data.inputs[inputParam.name] ?? '', inputParam)}
|
||||||
>
|
>
|
||||||
Format Prompt Values
|
{inputParam.label}
|
||||||
</Button>
|
</Button>
|
||||||
<FormatPromptValuesDialog
|
<FormatPromptValuesDialog
|
||||||
show={showFormatPromptValuesDialog}
|
show={showFormatPromptValuesDialog}
|
||||||
|
|
@ -428,6 +444,12 @@ const NodeInputHandler = ({ inputAnchor, inputParam, data, disabled = false, isA
|
||||||
onCancel={() => setAsyncOptionEditDialog('')}
|
onCancel={() => setAsyncOptionEditDialog('')}
|
||||||
onConfirm={onConfirmAsyncOption}
|
onConfirm={onConfirmAsyncOption}
|
||||||
></AssistantDialog>
|
></AssistantDialog>
|
||||||
|
<ExpandTextDialog
|
||||||
|
show={showExpandDialog}
|
||||||
|
dialogProps={expandDialogProps}
|
||||||
|
onCancel={() => setShowExpandDialog(false)}
|
||||||
|
onConfirm={(newValue, inputParamName) => onExpandDialogSave(newValue, inputParamName)}
|
||||||
|
></ExpandTextDialog>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,7 @@ import { TooltipWithParser } from 'ui-component/tooltip/TooltipWithParser'
|
||||||
import { GridActionsCellItem } from '@mui/x-data-grid'
|
import { GridActionsCellItem } from '@mui/x-data-grid'
|
||||||
import DeleteIcon from '@mui/icons-material/Delete'
|
import DeleteIcon from '@mui/icons-material/Delete'
|
||||||
import ConfirmDialog from 'ui-component/dialog/ConfirmDialog'
|
import ConfirmDialog from 'ui-component/dialog/ConfirmDialog'
|
||||||
import { DarkCodeEditor } from 'ui-component/editor/DarkCodeEditor'
|
import { CodeEditor } from 'ui-component/editor/CodeEditor'
|
||||||
import { LightCodeEditor } from 'ui-component/editor/LightCodeEditor'
|
|
||||||
import { useTheme } from '@mui/material/styles'
|
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
import { IconX, IconFileExport } from '@tabler/icons'
|
import { IconX, IconFileExport } from '@tabler/icons'
|
||||||
|
|
@ -56,7 +54,6 @@ try {
|
||||||
|
|
||||||
const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) => {
|
const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) => {
|
||||||
const portalElement = document.getElementById('portal')
|
const portalElement = document.getElementById('portal')
|
||||||
const theme = useTheme()
|
|
||||||
|
|
||||||
const customization = useSelector((state) => state.customization)
|
const customization = useSelector((state) => state.customization)
|
||||||
const dispatch = useDispatch()
|
const dispatch = useDispatch()
|
||||||
|
|
@ -490,32 +487,14 @@ const ToolDialog = ({ show, dialogProps, onUseTemplate, onCancel, onConfirm }) =
|
||||||
See Example
|
See Example
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
{customization.isDarkMode ? (
|
<CodeEditor
|
||||||
<DarkCodeEditor
|
disabled={dialogProps.type === 'TEMPLATE'}
|
||||||
value={toolFunc}
|
value={toolFunc}
|
||||||
disabled={dialogProps.type === 'TEMPLATE'}
|
height='calc(100vh - 220px)'
|
||||||
onValueChange={(code) => setToolFunc(code)}
|
theme={customization.isDarkMode ? 'dark' : 'light'}
|
||||||
style={{
|
lang={'js'}
|
||||||
fontSize: '0.875rem',
|
onValueChange={(code) => setToolFunc(code)}
|
||||||
minHeight: 'calc(100vh - 220px)',
|
/>
|
||||||
width: '100%',
|
|
||||||
borderRadius: 5
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<LightCodeEditor
|
|
||||||
value={toolFunc}
|
|
||||||
disabled={dialogProps.type === 'TEMPLATE'}
|
|
||||||
onValueChange={(code) => setToolFunc(code)}
|
|
||||||
style={{
|
|
||||||
fontSize: '0.875rem',
|
|
||||||
minHeight: 'calc(100vh - 220px)',
|
|
||||||
width: '100%',
|
|
||||||
border: `1px solid ${theme.palette.grey[300]}`,
|
|
||||||
borderRadius: 5
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Box>
|
</Box>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue