Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 5 additions & 70 deletions packages-answers/utils/src/extractAllCredentials.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,15 @@
import { getCredentialCategory } from './getCredentialCategory'
import { processFlowCredentials } from './processFlowCredentials'

/**
* Extract all credentials (assigned and unassigned) from flow data for QuickSetup mode
* @param {string|object} flowData - Flow data as JSON string or object
* @returns {object} Object containing all credentials info
*/
export const extractAllCredentials = (flowData: string | any) => {
Comment thread
maxtechera marked this conversation as resolved.
try {
// Parse flow data if it's a string
const flow = typeof flowData === 'string' ? JSON.parse(flowData) : flowData
const { credentials, hasCredentials } = processFlowCredentials(flowData)

if (!flow.nodes || !Array.isArray(flow.nodes)) {
return { allCredentials: [], hasCredentials: false }
}

const allCredentials: any[] = []
const credentialTypes = new Set<string>()

// Iterate through all nodes
flow.nodes.forEach((node: any) => {
if (node.data && node.data.inputParams) {
// Find all credential input parameters
const credentialParams = node.data.inputParams.filter((param: any) => {
return param.type === 'credential'
})

credentialParams.forEach((credentialParam: any) => {
// Check if credential is assigned
const hasCredential =
node.data.credential ||
(node.data.inputs && node.data.inputs[credentialParam.name]) ||
(node.data.inputs && node.data.inputs['FLOWISE_CREDENTIAL_ID'])

// Extract credential names
const credentialNames = credentialParam.credentialNames || []

credentialNames.forEach((credentialName: string) => {
credentialTypes.add(credentialName)

// Get category information to determine if credential is core
const category = getCredentialCategory(node.data.category, credentialName)

// Credential is required if:
// 1. Category is core (Chat Models, Agents, etc), OR
// 2. Parameter explicitly marked as NOT optional (optional: false)
// Default to optional if not explicitly marked
const isRequired = category.isCore || (credentialParam.optional === false)

const credInfo = {
nodeId: node.id,
nodeName: node.data.name || 'Unknown Node',
nodeCategory: node.data.category || 'Unknown',
nodeType: node.data.type || node.type || 'Unknown',
credentialType: credentialName,
parameterName: credentialParam.name,
label: credentialParam.label || credentialParam.name,
isRequired: isRequired,
isCore: category.isCore,
categoryType: category.type,
categoryDisplayName: category.displayName,
isAssigned: !!hasCredential,
assignedCredentialId: hasCredential || null
}

allCredentials.push(credInfo)
})
})
}
})

return {
allCredentials,
hasCredentials: credentialTypes.size > 0
}
} catch (error) {
console.error('Error in extractAllCredentials:', error)
return { allCredentials: [], hasCredentials: false }
return {
allCredentials: credentials,
hasCredentials
}
}
77 changes: 8 additions & 69 deletions packages-answers/utils/src/extractMissingCredentials.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,83 +2,22 @@
* Utility functions for detecting and managing missing credentials in flows
*/

import { getCredentialCategory } from './getCredentialCategory'
import { processFlowCredentials } from './processFlowCredentials'

/**
* Extract required credentials from flow data and identify missing ones
* @param {string|object} flowData - Flow data as JSON string or object
* @returns {object} Object containing missing credentials info
*/
export const extractMissingCredentials = (flowData: string | any) => {
try {
// Parse flow data if it's a string
const flow = typeof flowData === 'string' ? JSON.parse(flowData) : flowData
const { credentials, hasCredentials } = processFlowCredentials(flowData)

if (!flow.nodes || !Array.isArray(flow.nodes)) {
return { missingCredentials: [], hasCredentials: false }
}
const missingCredentials = credentials
.filter((credential) => !credential.isAssigned)
.map(({ isAssigned, assignedCredentialId, ...rest }) => rest)

const missingCredentials: any[] = []
const credentialTypes = new Set<string>()

// Iterate through all nodes
flow.nodes.forEach((node: any) => {
if (node.data && node.data.inputParams) {
// Find all credential input parameters
const credentialParams = node.data.inputParams.filter((param: any) => {
return param.type === 'credential'
})

credentialParams.forEach((credentialParam: any) => {
// Check if credential is assigned
const hasCredential =
node.data.credential ||
(node.data.inputs && node.data.inputs[credentialParam.name]) ||
(node.data.inputs && node.data.inputs['FLOWISE_CREDENTIAL_ID'])

if (!hasCredential) {
// Extract credential names
const credentialNames = credentialParam.credentialNames || []

credentialNames.forEach((credentialName: string) => {
credentialTypes.add(credentialName)

// Get category information to determine if credential is core
const category = getCredentialCategory(node.data.category, credentialName)

// Credential is required if:
// 1. Category is core (Chat Models, Agents, etc), OR
// 2. Parameter explicitly marked as NOT optional (optional: false)
// Default to optional if not explicitly marked
const isRequired = category.isCore || (credentialParam.optional === false)

const missingCred = {
nodeId: node.id,
nodeName: node.data.name || 'Unknown Node',
nodeCategory: node.data.category || 'Unknown',
nodeType: node.data.type || node.type || 'Unknown',
credentialType: credentialName,
parameterName: credentialParam.name,
label: credentialParam.label || credentialParam.name,
isRequired: isRequired,
isCore: category.isCore,
categoryType: category.type,
categoryDisplayName: category.displayName
}

missingCredentials.push(missingCred)
})
}
})
}
})

return {
missingCredentials,
hasCredentials: credentialTypes.size > 0
}
} catch (error) {
console.error('Error in extractMissingCredentials:', error)
return { missingCredentials: [], hasCredentials: false }
return {
missingCredentials,
hasCredentials
}
}
82 changes: 82 additions & 0 deletions packages-answers/utils/src/processFlowCredentials.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { getCredentialCategory } from './getCredentialCategory'

type FlowData = string | Record<string, any>

export type FlowCredentialRecord = {
nodeId: string
nodeName: string
nodeCategory: string
nodeType: string
credentialType: string
parameterName: string
label: string
isRequired: boolean
isCore: boolean
categoryType: string
categoryDisplayName: string
isAssigned: boolean
assignedCredentialId: string | null
}

type ProcessResult = {
credentials: FlowCredentialRecord[]
hasCredentials: boolean
}

export const processFlowCredentials = (flowData: FlowData): ProcessResult => {
try {
const flow = typeof flowData === 'string' ? JSON.parse(flowData) : flowData

if (!flow || !Array.isArray(flow.nodes)) {
return { credentials: [], hasCredentials: false }
}

const credentials: FlowCredentialRecord[] = []
const credentialTypes = new Set<string>()

flow.nodes.forEach((node: any) => {
const inputParams = node?.data?.inputParams
if (!Array.isArray(inputParams)) return

const credentialParams = inputParams.filter((param: any) => param?.type === 'credential')

credentialParams.forEach((credentialParam: any) => {
const inputs = node?.data?.inputs
const hasCredential =
node?.data?.credential || (inputs && (inputs[credentialParam.name] || inputs['FLOWISE_CREDENTIAL_ID']))

const credentialNames: string[] = credentialParam?.credentialNames || []

credentialNames.forEach((credentialName: string) => {
credentialTypes.add(credentialName)

const category = getCredentialCategory(node?.data?.category, credentialName)
const isRequired = category.isCore || credentialParam?.optional === false

credentials.push({
nodeId: node?.id,
nodeName: node?.data?.name || 'Unknown Node',
nodeCategory: node?.data?.category || 'Unknown',
nodeType: node?.data?.type || node?.type || 'Unknown',
credentialType: credentialName,
parameterName: credentialParam?.name,
label: credentialParam?.label || credentialParam?.name,
isRequired,
isCore: category.isCore,
categoryType: category.type,
categoryDisplayName: category.displayName,
isAssigned: !!hasCredential,
assignedCredentialId: hasCredential || null
})
})
})
})

return {
credentials,
hasCredentials: credentialTypes.size > 0
}
} catch (_error) {
return { credentials: [], hasCredentials: false }
}
}
Loading
Loading