|
import moment from 'moment' |
|
|
|
export const getUniqueNodeId = (nodeData, nodes) => { |
|
|
|
let totalSameNodes = 0 |
|
for (let i = 0; i < nodes.length; i += 1) { |
|
const node = nodes[i] |
|
if (node.data.name === nodeData.name) { |
|
totalSameNodes += 1 |
|
} |
|
} |
|
|
|
|
|
let nodeId = `${nodeData.name}_${totalSameNodes}` |
|
for (let i = 0; i < nodes.length; i += 1) { |
|
const node = nodes[i] |
|
if (node.id === nodeId) { |
|
totalSameNodes += 1 |
|
nodeId = `${nodeData.name}_${totalSameNodes}` |
|
} |
|
} |
|
return nodeId |
|
} |
|
|
|
export const initializeDefaultNodeData = (nodeParams) => { |
|
const initialValues = {} |
|
|
|
for (let i = 0; i < nodeParams.length; i += 1) { |
|
const input = nodeParams[i] |
|
initialValues[input.name] = input.default || '' |
|
} |
|
|
|
return initialValues |
|
} |
|
|
|
export const initNode = (nodeData, newNodeId) => { |
|
const inputAnchors = [] |
|
const inputParams = [] |
|
const incoming = nodeData.inputs ? nodeData.inputs.length : 0 |
|
const outgoing = 1 |
|
|
|
const whitelistTypes = ['options', 'string', 'number', 'boolean', 'password', 'json', 'code', 'date', 'file', 'folder'] |
|
|
|
for (let i = 0; i < incoming; i += 1) { |
|
const newInput = { |
|
...nodeData.inputs[i], |
|
id: `${newNodeId}-input-${nodeData.inputs[i].name}-${nodeData.inputs[i].type}` |
|
} |
|
if (whitelistTypes.includes(nodeData.inputs[i].type)) { |
|
inputParams.push(newInput) |
|
} else { |
|
inputAnchors.push(newInput) |
|
} |
|
} |
|
|
|
const outputAnchors = [] |
|
for (let i = 0; i < outgoing; i += 1) { |
|
if (nodeData.outputs && nodeData.outputs.length) { |
|
const options = [] |
|
for (let j = 0; j < nodeData.outputs.length; j += 1) { |
|
let baseClasses = '' |
|
let type = '' |
|
|
|
const outputBaseClasses = nodeData.outputs[j].baseClasses ?? [] |
|
if (outputBaseClasses.length > 1) { |
|
baseClasses = outputBaseClasses.join('|') |
|
type = outputBaseClasses.join(' | ') |
|
} else if (outputBaseClasses.length === 1) { |
|
baseClasses = outputBaseClasses[0] |
|
type = outputBaseClasses[0] |
|
} |
|
|
|
const newOutputOption = { |
|
id: `${newNodeId}-output-${nodeData.outputs[j].name}-${baseClasses}`, |
|
name: nodeData.outputs[j].name, |
|
label: nodeData.outputs[j].label, |
|
type |
|
} |
|
options.push(newOutputOption) |
|
} |
|
const newOutput = { |
|
name: 'output', |
|
label: 'Output', |
|
type: 'options', |
|
options, |
|
default: nodeData.outputs[0].name |
|
} |
|
outputAnchors.push(newOutput) |
|
} else { |
|
const newOutput = { |
|
id: `${newNodeId}-output-${nodeData.name}-${nodeData.baseClasses.join('|')}`, |
|
name: nodeData.name, |
|
label: nodeData.type, |
|
type: nodeData.baseClasses.join(' | ') |
|
} |
|
outputAnchors.push(newOutput) |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (nodeData.inputs) { |
|
nodeData.inputAnchors = inputAnchors |
|
nodeData.inputParams = inputParams |
|
nodeData.inputs = initializeDefaultNodeData(nodeData.inputs) |
|
} else { |
|
nodeData.inputAnchors = [] |
|
nodeData.inputParams = [] |
|
nodeData.inputs = {} |
|
} |
|
|
|
if (nodeData.outputs) { |
|
nodeData.outputs = initializeDefaultNodeData(outputAnchors) |
|
} else { |
|
nodeData.outputs = {} |
|
} |
|
|
|
nodeData.outputAnchors = outputAnchors |
|
nodeData.id = newNodeId |
|
|
|
return nodeData |
|
} |
|
|
|
export const getEdgeLabelName = (source) => { |
|
const sourceSplit = source.split('-') |
|
if (sourceSplit.length && sourceSplit[0].includes('ifElse')) { |
|
const outputAnchorsIndex = sourceSplit[sourceSplit.length - 1] |
|
return outputAnchorsIndex === '0' ? 'true' : 'false' |
|
} |
|
return '' |
|
} |
|
|
|
export const isValidConnection = (connection, reactFlowInstance) => { |
|
const sourceHandle = connection.sourceHandle |
|
const targetHandle = connection.targetHandle |
|
const target = connection.target |
|
|
|
|
|
|
|
|
|
const sourceTypes = sourceHandle.split('-')[sourceHandle.split('-').length - 1].split('|') |
|
const targetTypes = targetHandle.split('-')[targetHandle.split('-').length - 1].split('|') |
|
|
|
if (targetTypes.some((t) => sourceTypes.includes(t))) { |
|
let targetNode = reactFlowInstance.getNode(target) |
|
|
|
if (!targetNode) { |
|
if (!reactFlowInstance.getEdges().find((e) => e.targetHandle === targetHandle)) { |
|
return true |
|
} |
|
} else { |
|
const targetNodeInputAnchor = |
|
targetNode.data.inputAnchors.find((ancr) => ancr.id === targetHandle) || |
|
targetNode.data.inputParams.find((ancr) => ancr.id === targetHandle) |
|
if ( |
|
(targetNodeInputAnchor && |
|
!targetNodeInputAnchor?.list && |
|
!reactFlowInstance.getEdges().find((e) => e.targetHandle === targetHandle)) || |
|
targetNodeInputAnchor?.list |
|
) { |
|
return true |
|
} |
|
} |
|
} |
|
return false |
|
} |
|
|
|
export const convertDateStringToDateObject = (dateString) => { |
|
if (dateString === undefined || !dateString) return undefined |
|
|
|
const date = moment(dateString) |
|
if (!date.isValid) return undefined |
|
|
|
|
|
return new Date(date.year(), date.month(), date.date(), date.hours(), date.minutes()) |
|
} |
|
|
|
export const getFileName = (fileBase64) => { |
|
let fileNames = [] |
|
if (fileBase64.startsWith('[') && fileBase64.endsWith(']')) { |
|
const files = JSON.parse(fileBase64) |
|
for (const file of files) { |
|
const splitDataURI = file.split(',') |
|
const filename = splitDataURI[splitDataURI.length - 1].split(':')[1] |
|
fileNames.push(filename) |
|
} |
|
return fileNames.join(', ') |
|
} else { |
|
const splitDataURI = fileBase64.split(',') |
|
const filename = splitDataURI[splitDataURI.length - 1].split(':')[1] |
|
return filename |
|
} |
|
} |
|
|
|
export const getFolderName = (base64ArrayStr) => { |
|
try { |
|
const base64Array = JSON.parse(base64ArrayStr) |
|
const filenames = [] |
|
for (let i = 0; i < base64Array.length; i += 1) { |
|
const fileBase64 = base64Array[i] |
|
const splitDataURI = fileBase64.split(',') |
|
const filename = splitDataURI[splitDataURI.length - 1].split(':')[1] |
|
filenames.push(filename) |
|
} |
|
return filenames.length ? filenames.join(',') : '' |
|
} catch (e) { |
|
return '' |
|
} |
|
} |
|
|
|
export const generateExportFlowData = (flowData) => { |
|
const nodes = flowData.nodes |
|
const edges = flowData.edges |
|
|
|
for (let i = 0; i < nodes.length; i += 1) { |
|
nodes[i].selected = false |
|
const node = nodes[i] |
|
|
|
const newNodeData = { |
|
id: node.data.id, |
|
label: node.data.label, |
|
name: node.data.name, |
|
type: node.data.type, |
|
baseClasses: node.data.baseClasses, |
|
category: node.data.category, |
|
description: node.data.description, |
|
inputParams: node.data.inputParams, |
|
inputAnchors: node.data.inputAnchors, |
|
inputs: {}, |
|
outputAnchors: node.data.outputAnchors, |
|
outputs: node.data.outputs, |
|
selected: false |
|
} |
|
|
|
|
|
if (node.data.inputs && Object.keys(node.data.inputs).length) { |
|
const nodeDataInputs = {} |
|
for (const input in node.data.inputs) { |
|
const inputParam = node.data.inputParams.find((inp) => inp.name === input) |
|
if (inputParam && inputParam.type === 'password') continue |
|
if (inputParam && inputParam.type === 'file') continue |
|
if (inputParam && inputParam.type === 'folder') continue |
|
nodeDataInputs[input] = node.data.inputs[input] |
|
} |
|
newNodeData.inputs = nodeDataInputs |
|
} |
|
|
|
nodes[i].data = newNodeData |
|
} |
|
const exportJson = { |
|
nodes, |
|
edges |
|
} |
|
return exportJson |
|
} |
|
|
|
export const getAvailableNodesForVariable = (nodes, edges, target, targetHandle) => { |
|
|
|
|
|
const parentNodes = [] |
|
const inputEdges = edges.filter((edg) => edg.target === target && edg.targetHandle === targetHandle) |
|
if (inputEdges && inputEdges.length) { |
|
for (let j = 0; j < inputEdges.length; j += 1) { |
|
const node = nodes.find((nd) => nd.id === inputEdges[j].source) |
|
parentNodes.push(node) |
|
} |
|
} |
|
return parentNodes |
|
} |
|
|
|
export const rearrangeToolsOrdering = (newValues, sourceNodeId) => { |
|
|
|
newValues.push(`{{${sourceNodeId}.data.instance}}`) |
|
|
|
const sortKey = (item) => { |
|
if (item.includes('requestsGet') || item.includes('readFile')) { |
|
return 0 |
|
} else if (item.includes('requestsPost') || item.includes('writeFile')) { |
|
return 1 |
|
} else { |
|
return 2 |
|
} |
|
} |
|
|
|
newValues.sort((a, b) => sortKey(a) - sortKey(b)) |
|
} |
|
|
|
export const throttle = (func, limit) => { |
|
let lastFunc |
|
let lastRan |
|
|
|
return (...args) => { |
|
if (!lastRan) { |
|
func(...args) |
|
lastRan = Date.now() |
|
} else { |
|
clearTimeout(lastFunc) |
|
lastFunc = setTimeout(() => { |
|
if (Date.now() - lastRan >= limit) { |
|
func(...args) |
|
lastRan = Date.now() |
|
} |
|
}, limit - (Date.now() - lastRan)) |
|
} |
|
} |
|
} |
|
|