mirror of
https://github.com/simstudioai/sim.git
synced 2026-03-15 03:00:33 -04:00
Compare commits
4 Commits
v0.5.108
...
improvemen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc5df60d8f | ||
|
|
adea9db89d | ||
|
|
94abc424be | ||
|
|
c1c6ed66d1 |
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useParams } from 'next/navigation'
|
import { useParams } from 'next/navigation'
|
||||||
|
import { SELECTOR_CONTEXT_FIELDS } from '@/lib/workflows/subblocks/context'
|
||||||
import type { SubBlockConfig } from '@/blocks/types'
|
import type { SubBlockConfig } from '@/blocks/types'
|
||||||
import { extractEnvVarName, isEnvVarReference, isReference } from '@/executor/constants'
|
import { extractEnvVarName, isEnvVarReference, isReference } from '@/executor/constants'
|
||||||
import type { SelectorContext, SelectorKey } from '@/hooks/selectors/types'
|
import type { SelectorContext, SelectorKey } from '@/hooks/selectors/types'
|
||||||
@@ -14,8 +15,7 @@ import { useDependsOnGate } from './use-depends-on-gate'
|
|||||||
*
|
*
|
||||||
* Builds a `SelectorContext` by mapping each `dependsOn` entry through the
|
* Builds a `SelectorContext` by mapping each `dependsOn` entry through the
|
||||||
* canonical index to its `canonicalParamId`, which maps directly to
|
* canonical index to its `canonicalParamId`, which maps directly to
|
||||||
* `SelectorContext` field names (e.g. `siteId`, `teamId`, `collectionId`).
|
* `SelectorContext` field names (e.g. `siteId`, `teamId`, `oauthCredential`).
|
||||||
* The one special case is `oauthCredential` which maps to `credentialId`.
|
|
||||||
*
|
*
|
||||||
* @param blockId - The block containing the selector sub-block
|
* @param blockId - The block containing the selector sub-block
|
||||||
* @param subBlock - The sub-block config (must have `selectorKey` set)
|
* @param subBlock - The sub-block config (must have `selectorKey` set)
|
||||||
@@ -70,11 +70,8 @@ export function useSelectorSetup(
|
|||||||
if (isReference(strValue)) continue
|
if (isReference(strValue)) continue
|
||||||
|
|
||||||
const canonicalParamId = canonicalIndex.canonicalIdBySubBlockId[depKey] ?? depKey
|
const canonicalParamId = canonicalIndex.canonicalIdBySubBlockId[depKey] ?? depKey
|
||||||
|
if (SELECTOR_CONTEXT_FIELDS.has(canonicalParamId as keyof SelectorContext)) {
|
||||||
if (canonicalParamId === 'oauthCredential') {
|
context[canonicalParamId as keyof SelectorContext] = strValue
|
||||||
context.credentialId = strValue
|
|
||||||
} else if (canonicalParamId in CONTEXT_FIELD_SET) {
|
|
||||||
;(context as Record<string, unknown>)[canonicalParamId] = strValue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,19 +86,3 @@ export function useSelectorSetup(
|
|||||||
dependencyValues: resolvedDependencyValues,
|
dependencyValues: resolvedDependencyValues,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const CONTEXT_FIELD_SET: Record<string, true> = {
|
|
||||||
credentialId: true,
|
|
||||||
domain: true,
|
|
||||||
teamId: true,
|
|
||||||
projectId: true,
|
|
||||||
knowledgeBaseId: true,
|
|
||||||
planId: true,
|
|
||||||
siteId: true,
|
|
||||||
collectionId: true,
|
|
||||||
spreadsheetId: true,
|
|
||||||
fileId: true,
|
|
||||||
baseId: true,
|
|
||||||
datasetId: true,
|
|
||||||
serviceDeskId: true,
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -57,9 +57,9 @@ import { useWebhookManagement } from '@/hooks/use-webhook-management'
|
|||||||
const SLACK_OVERRIDES: SelectorOverrides = {
|
const SLACK_OVERRIDES: SelectorOverrides = {
|
||||||
transformContext: (context, deps) => {
|
transformContext: (context, deps) => {
|
||||||
const authMethod = deps.authMethod as string
|
const authMethod = deps.authMethod as string
|
||||||
const credentialId =
|
const oauthCredential =
|
||||||
authMethod === 'bot_token' ? String(deps.botToken ?? '') : String(deps.credential ?? '')
|
authMethod === 'bot_token' ? String(deps.botToken ?? '') : String(deps.credential ?? '')
|
||||||
return { ...context, credentialId }
|
return { ...context, oauthCredential }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -578,7 +578,7 @@ const SubBlockRow = memo(function SubBlockRow({
|
|||||||
subBlock,
|
subBlock,
|
||||||
value: rawValue,
|
value: rawValue,
|
||||||
workflowId,
|
workflowId,
|
||||||
credentialId: typeof credentialId === 'string' ? credentialId : undefined,
|
oauthCredential: typeof credentialId === 'string' ? credentialId : undefined,
|
||||||
knowledgeBaseId: typeof knowledgeBaseId === 'string' ? knowledgeBaseId : undefined,
|
knowledgeBaseId: typeof knowledgeBaseId === 'string' ? knowledgeBaseId : undefined,
|
||||||
domain: domainValue,
|
domain: domainValue,
|
||||||
teamId: teamIdValue,
|
teamId: teamIdValue,
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ type FolderResponse = { id: string; name: string }
|
|||||||
type PlannerTask = { id: string; title: string }
|
type PlannerTask = { id: string; title: string }
|
||||||
|
|
||||||
const ensureCredential = (context: SelectorContext, key: SelectorKey): string => {
|
const ensureCredential = (context: SelectorContext, key: SelectorKey): string => {
|
||||||
if (!context.credentialId) {
|
if (!context.oauthCredential) {
|
||||||
throw new Error(`Missing credential for selector ${key}`)
|
throw new Error(`Missing credential for selector ${key}`)
|
||||||
}
|
}
|
||||||
return context.credentialId
|
return context.oauthCredential
|
||||||
}
|
}
|
||||||
|
|
||||||
const ensureDomain = (context: SelectorContext, key: SelectorKey): string => {
|
const ensureDomain = (context: SelectorContext, key: SelectorKey): string => {
|
||||||
@@ -66,9 +66,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'airtable.bases',
|
'airtable.bases',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'airtable.bases')
|
const credentialId = ensureCredential(context, 'airtable.bases')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -104,10 +104,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'airtable.tables',
|
'airtable.tables',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.baseId ?? 'none',
|
context.baseId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.baseId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.baseId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'airtable.tables')
|
const credentialId = ensureCredential(context, 'airtable.tables')
|
||||||
if (!context.baseId) {
|
if (!context.baseId) {
|
||||||
@@ -151,9 +151,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'asana.workspaces',
|
'asana.workspaces',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'asana.workspaces')
|
const credentialId = ensureCredential(context, 'asana.workspaces')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -182,9 +182,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'attio.objects',
|
'attio.objects',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'attio.objects')
|
const credentialId = ensureCredential(context, 'attio.objects')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -216,9 +216,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'attio.lists',
|
'attio.lists',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'attio.lists')
|
const credentialId = ensureCredential(context, 'attio.lists')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -250,10 +250,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'bigquery.datasets',
|
'bigquery.datasets',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.projectId ?? 'none',
|
context.projectId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.projectId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.projectId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'bigquery.datasets')
|
const credentialId = ensureCredential(context, 'bigquery.datasets')
|
||||||
if (!context.projectId) throw new Error('Missing project ID for bigquery.datasets selector')
|
if (!context.projectId) throw new Error('Missing project ID for bigquery.datasets selector')
|
||||||
@@ -298,12 +298,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'bigquery.tables',
|
'bigquery.tables',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.projectId ?? 'none',
|
context.projectId ?? 'none',
|
||||||
context.datasetId ?? 'none',
|
context.datasetId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) =>
|
enabled: ({ context }) =>
|
||||||
Boolean(context.credentialId && context.projectId && context.datasetId),
|
Boolean(context.oauthCredential && context.projectId && context.datasetId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'bigquery.tables')
|
const credentialId = ensureCredential(context, 'bigquery.tables')
|
||||||
if (!context.projectId) throw new Error('Missing project ID for bigquery.tables selector')
|
if (!context.projectId) throw new Error('Missing project ID for bigquery.tables selector')
|
||||||
@@ -347,9 +347,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'calcom.eventTypes',
|
'calcom.eventTypes',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'calcom.eventTypes')
|
const credentialId = ensureCredential(context, 'calcom.eventTypes')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -381,9 +381,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'calcom.schedules',
|
'calcom.schedules',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'calcom.schedules')
|
const credentialId = ensureCredential(context, 'calcom.schedules')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -415,10 +415,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'confluence.spaces',
|
'confluence.spaces',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.domain ?? 'none',
|
context.domain ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.domain),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.domain),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'confluence.spaces')
|
const credentialId = ensureCredential(context, 'confluence.spaces')
|
||||||
const domain = ensureDomain(context, 'confluence.spaces')
|
const domain = ensureDomain(context, 'confluence.spaces')
|
||||||
@@ -460,10 +460,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'jsm.serviceDesks',
|
'jsm.serviceDesks',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.domain ?? 'none',
|
context.domain ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.domain),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.domain),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'jsm.serviceDesks')
|
const credentialId = ensureCredential(context, 'jsm.serviceDesks')
|
||||||
const domain = ensureDomain(context, 'jsm.serviceDesks')
|
const domain = ensureDomain(context, 'jsm.serviceDesks')
|
||||||
@@ -505,12 +505,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'jsm.requestTypes',
|
'jsm.requestTypes',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.domain ?? 'none',
|
context.domain ?? 'none',
|
||||||
context.serviceDeskId ?? 'none',
|
context.serviceDeskId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) =>
|
enabled: ({ context }) =>
|
||||||
Boolean(context.credentialId && context.domain && context.serviceDeskId),
|
Boolean(context.oauthCredential && context.domain && context.serviceDeskId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'jsm.requestTypes')
|
const credentialId = ensureCredential(context, 'jsm.requestTypes')
|
||||||
const domain = ensureDomain(context, 'jsm.requestTypes')
|
const domain = ensureDomain(context, 'jsm.requestTypes')
|
||||||
@@ -556,9 +556,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'google.tasks.lists',
|
'google.tasks.lists',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'google.tasks.lists')
|
const credentialId = ensureCredential(context, 'google.tasks.lists')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -587,9 +587,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.planner.plans',
|
'microsoft.planner.plans',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'microsoft.planner.plans')
|
const credentialId = ensureCredential(context, 'microsoft.planner.plans')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -618,9 +618,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'notion.databases',
|
'notion.databases',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'notion.databases')
|
const credentialId = ensureCredential(context, 'notion.databases')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -652,9 +652,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'notion.pages',
|
'notion.pages',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'notion.pages')
|
const credentialId = ensureCredential(context, 'notion.pages')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -686,9 +686,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'pipedrive.pipelines',
|
'pipedrive.pipelines',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'pipedrive.pipelines')
|
const credentialId = ensureCredential(context, 'pipedrive.pipelines')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -720,10 +720,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'sharepoint.lists',
|
'sharepoint.lists',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.siteId ?? 'none',
|
context.siteId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.siteId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.siteId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'sharepoint.lists')
|
const credentialId = ensureCredential(context, 'sharepoint.lists')
|
||||||
if (!context.siteId) throw new Error('Missing site ID for sharepoint.lists selector')
|
if (!context.siteId) throw new Error('Missing site ID for sharepoint.lists selector')
|
||||||
@@ -761,9 +761,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'trello.boards',
|
'trello.boards',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'trello.boards')
|
const credentialId = ensureCredential(context, 'trello.boards')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -794,9 +794,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'zoom.meetings',
|
'zoom.meetings',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'zoom.meetings')
|
const credentialId = ensureCredential(context, 'zoom.meetings')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -828,12 +828,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'slack.channels',
|
'slack.channels',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
credential: context.credentialId,
|
credential: context.oauthCredential,
|
||||||
workflowId: context.workflowId,
|
workflowId: context.workflowId,
|
||||||
})
|
})
|
||||||
const data = await fetchJson<{ channels: SlackChannel[] }>('/api/tools/slack/channels', {
|
const data = await fetchJson<{ channels: SlackChannel[] }>('/api/tools/slack/channels', {
|
||||||
@@ -852,12 +852,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'slack.users',
|
'slack.users',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
credential: context.credentialId,
|
credential: context.oauthCredential,
|
||||||
workflowId: context.workflowId,
|
workflowId: context.workflowId,
|
||||||
})
|
})
|
||||||
const data = await fetchJson<{ users: SlackUser[] }>('/api/tools/slack/users', {
|
const data = await fetchJson<{ users: SlackUser[] }>('/api/tools/slack/users', {
|
||||||
@@ -876,12 +876,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'gmail.labels',
|
'gmail.labels',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const data = await fetchJson<{ labels: FolderResponse[] }>('/api/tools/gmail/labels', {
|
const data = await fetchJson<{ labels: FolderResponse[] }>('/api/tools/gmail/labels', {
|
||||||
searchParams: { credentialId: context.credentialId },
|
searchParams: { credentialId: context.oauthCredential },
|
||||||
})
|
})
|
||||||
return (data.labels || []).map((label) => ({
|
return (data.labels || []).map((label) => ({
|
||||||
id: label.id,
|
id: label.id,
|
||||||
@@ -895,12 +895,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'outlook.folders',
|
'outlook.folders',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const data = await fetchJson<{ folders: FolderResponse[] }>('/api/tools/outlook/folders', {
|
const data = await fetchJson<{ folders: FolderResponse[] }>('/api/tools/outlook/folders', {
|
||||||
searchParams: { credentialId: context.credentialId },
|
searchParams: { credentialId: context.oauthCredential },
|
||||||
})
|
})
|
||||||
return (data.folders || []).map((folder) => ({
|
return (data.folders || []).map((folder) => ({
|
||||||
id: folder.id,
|
id: folder.id,
|
||||||
@@ -914,13 +914,13 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'google.calendar',
|
'google.calendar',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const data = await fetchJson<{ calendars: { id: string; summary: string }[] }>(
|
const data = await fetchJson<{ calendars: { id: string; summary: string }[] }>(
|
||||||
'/api/tools/google_calendar/calendars',
|
'/api/tools/google_calendar/calendars',
|
||||||
{ searchParams: { credentialId: context.credentialId } }
|
{ searchParams: { credentialId: context.oauthCredential } }
|
||||||
)
|
)
|
||||||
return (data.calendars || []).map((calendar) => ({
|
return (data.calendars || []).map((calendar) => ({
|
||||||
id: calendar.id,
|
id: calendar.id,
|
||||||
@@ -934,11 +934,11 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.teams',
|
'microsoft.teams',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const body = JSON.stringify({ credential: context.credentialId })
|
const body = JSON.stringify({ credential: context.oauthCredential })
|
||||||
const data = await fetchJson<{ teams: { id: string; displayName: string }[] }>(
|
const data = await fetchJson<{ teams: { id: string; displayName: string }[] }>(
|
||||||
'/api/tools/microsoft-teams/teams',
|
'/api/tools/microsoft-teams/teams',
|
||||||
{ method: 'POST', body }
|
{ method: 'POST', body }
|
||||||
@@ -955,11 +955,11 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.chats',
|
'microsoft.chats',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const body = JSON.stringify({ credential: context.credentialId })
|
const body = JSON.stringify({ credential: context.oauthCredential })
|
||||||
const data = await fetchJson<{ chats: { id: string; displayName: string }[] }>(
|
const data = await fetchJson<{ chats: { id: string; displayName: string }[] }>(
|
||||||
'/api/tools/microsoft-teams/chats',
|
'/api/tools/microsoft-teams/chats',
|
||||||
{ method: 'POST', body }
|
{ method: 'POST', body }
|
||||||
@@ -976,13 +976,13 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.channels',
|
'microsoft.channels',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.teamId ?? 'none',
|
context.teamId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.teamId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.teamId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
credential: context.credentialId,
|
credential: context.oauthCredential,
|
||||||
teamId: context.teamId,
|
teamId: context.teamId,
|
||||||
})
|
})
|
||||||
const data = await fetchJson<{ channels: { id: string; displayName: string }[] }>(
|
const data = await fetchJson<{ channels: { id: string; displayName: string }[] }>(
|
||||||
@@ -1001,14 +1001,14 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'wealthbox.contacts',
|
'wealthbox.contacts',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const data = await fetchJson<{ items: { id: string; name: string }[] }>(
|
const data = await fetchJson<{ items: { id: string; name: string }[] }>(
|
||||||
'/api/tools/wealthbox/items',
|
'/api/tools/wealthbox/items',
|
||||||
{
|
{
|
||||||
searchParams: { credentialId: context.credentialId, type: 'contact' },
|
searchParams: { credentialId: context.oauthCredential, type: 'contact' },
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
return (data.items || []).map((item) => ({
|
return (data.items || []).map((item) => ({
|
||||||
@@ -1023,9 +1023,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'sharepoint.sites',
|
'sharepoint.sites',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'sharepoint.sites')
|
const credentialId = ensureCredential(context, 'sharepoint.sites')
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
@@ -1069,10 +1069,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.planner',
|
'microsoft.planner',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.planId ?? 'none',
|
context.planId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.planId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.planId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'microsoft.planner')
|
const credentialId = ensureCredential(context, 'microsoft.planner')
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
@@ -1112,11 +1112,11 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'jira.projects',
|
'jira.projects',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.domain ?? 'none',
|
context.domain ?? 'none',
|
||||||
search ?? '',
|
search ?? '',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.domain),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.domain),
|
||||||
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'jira.projects')
|
const credentialId = ensureCredential(context, 'jira.projects')
|
||||||
const domain = ensureDomain(context, 'jira.projects')
|
const domain = ensureDomain(context, 'jira.projects')
|
||||||
@@ -1171,12 +1171,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'jira.issues',
|
'jira.issues',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.domain ?? 'none',
|
context.domain ?? 'none',
|
||||||
context.projectId ?? 'none',
|
context.projectId ?? 'none',
|
||||||
search ?? '',
|
search ?? '',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.domain),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.domain),
|
||||||
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'jira.issues')
|
const credentialId = ensureCredential(context, 'jira.issues')
|
||||||
const domain = ensureDomain(context, 'jira.issues')
|
const domain = ensureDomain(context, 'jira.issues')
|
||||||
@@ -1235,9 +1235,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'linear.teams',
|
'linear.teams',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'linear.teams')
|
const credentialId = ensureCredential(context, 'linear.teams')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -1260,10 +1260,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'linear.projects',
|
'linear.projects',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.teamId ?? 'none',
|
context.teamId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.teamId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.teamId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'linear.projects')
|
const credentialId = ensureCredential(context, 'linear.projects')
|
||||||
const body = JSON.stringify({
|
const body = JSON.stringify({
|
||||||
@@ -1290,11 +1290,11 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'confluence.pages',
|
'confluence.pages',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.domain ?? 'none',
|
context.domain ?? 'none',
|
||||||
search ?? '',
|
search ?? '',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.domain),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.domain),
|
||||||
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'confluence.pages')
|
const credentialId = ensureCredential(context, 'confluence.pages')
|
||||||
const domain = ensureDomain(context, 'confluence.pages')
|
const domain = ensureDomain(context, 'confluence.pages')
|
||||||
@@ -1343,9 +1343,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'onedrive.files',
|
'onedrive.files',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'onedrive.files')
|
const credentialId = ensureCredential(context, 'onedrive.files')
|
||||||
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
||||||
@@ -1366,9 +1366,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'onedrive.folders',
|
'onedrive.folders',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'onedrive.folders')
|
const credentialId = ensureCredential(context, 'onedrive.folders')
|
||||||
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
||||||
@@ -1389,12 +1389,12 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'google.drive',
|
'google.drive',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.mimeType ?? 'any',
|
context.mimeType ?? 'any',
|
||||||
context.fileId ?? 'root',
|
context.fileId ?? 'root',
|
||||||
search ?? '',
|
search ?? '',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'google.drive')
|
const credentialId = ensureCredential(context, 'google.drive')
|
||||||
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
||||||
@@ -1438,10 +1438,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'google.sheets',
|
'google.sheets',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.spreadsheetId ?? 'none',
|
context.spreadsheetId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.spreadsheetId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.spreadsheetId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'google.sheets')
|
const credentialId = ensureCredential(context, 'google.sheets')
|
||||||
if (!context.spreadsheetId) {
|
if (!context.spreadsheetId) {
|
||||||
@@ -1469,10 +1469,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.excel.sheets',
|
'microsoft.excel.sheets',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.spreadsheetId ?? 'none',
|
context.spreadsheetId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.spreadsheetId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.spreadsheetId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'microsoft.excel.sheets')
|
const credentialId = ensureCredential(context, 'microsoft.excel.sheets')
|
||||||
if (!context.spreadsheetId) {
|
if (!context.spreadsheetId) {
|
||||||
@@ -1500,10 +1500,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.excel',
|
'microsoft.excel',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
search ?? '',
|
search ?? '',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'microsoft.excel')
|
const credentialId = ensureCredential(context, 'microsoft.excel')
|
||||||
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
||||||
@@ -1528,10 +1528,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'microsoft.word',
|
'microsoft.word',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
search ?? '',
|
search ?? '',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'microsoft.word')
|
const credentialId = ensureCredential(context, 'microsoft.word')
|
||||||
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
const data = await fetchJson<{ files: { id: string; name: string }[] }>(
|
||||||
@@ -1596,9 +1596,9 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'webflow.sites',
|
'webflow.sites',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId),
|
enabled: ({ context }) => Boolean(context.oauthCredential),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'webflow.sites')
|
const credentialId = ensureCredential(context, 'webflow.sites')
|
||||||
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
const body = JSON.stringify({ credential: credentialId, workflowId: context.workflowId })
|
||||||
@@ -1621,10 +1621,10 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
getQueryKey: ({ context }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'webflow.collections',
|
'webflow.collections',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.siteId ?? 'none',
|
context.siteId ?? 'none',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.siteId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.siteId),
|
||||||
fetchList: async ({ context }: SelectorQueryArgs) => {
|
fetchList: async ({ context }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'webflow.collections')
|
const credentialId = ensureCredential(context, 'webflow.collections')
|
||||||
if (!context.siteId) {
|
if (!context.siteId) {
|
||||||
@@ -1654,11 +1654,11 @@ const registry: Record<SelectorKey, SelectorDefinition> = {
|
|||||||
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
getQueryKey: ({ context, search }: SelectorQueryArgs) => [
|
||||||
'selectors',
|
'selectors',
|
||||||
'webflow.items',
|
'webflow.items',
|
||||||
context.credentialId ?? 'none',
|
context.oauthCredential ?? 'none',
|
||||||
context.collectionId ?? 'none',
|
context.collectionId ?? 'none',
|
||||||
search ?? '',
|
search ?? '',
|
||||||
],
|
],
|
||||||
enabled: ({ context }) => Boolean(context.credentialId && context.collectionId),
|
enabled: ({ context }) => Boolean(context.oauthCredential && context.collectionId),
|
||||||
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
fetchList: async ({ context, search }: SelectorQueryArgs) => {
|
||||||
const credentialId = ensureCredential(context, 'webflow.items')
|
const credentialId = ensureCredential(context, 'webflow.items')
|
||||||
if (!context.collectionId) {
|
if (!context.collectionId) {
|
||||||
|
|||||||
@@ -7,46 +7,16 @@ export interface SelectorResolution {
|
|||||||
allowSearch: boolean
|
allowSearch: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectorResolutionArgs {
|
|
||||||
workflowId?: string
|
|
||||||
credentialId?: string
|
|
||||||
domain?: string
|
|
||||||
projectId?: string
|
|
||||||
planId?: string
|
|
||||||
teamId?: string
|
|
||||||
knowledgeBaseId?: string
|
|
||||||
siteId?: string
|
|
||||||
collectionId?: string
|
|
||||||
spreadsheetId?: string
|
|
||||||
fileId?: string
|
|
||||||
baseId?: string
|
|
||||||
datasetId?: string
|
|
||||||
serviceDeskId?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resolveSelectorForSubBlock(
|
export function resolveSelectorForSubBlock(
|
||||||
subBlock: SubBlockConfig,
|
subBlock: SubBlockConfig,
|
||||||
args: SelectorResolutionArgs
|
context: SelectorContext
|
||||||
): SelectorResolution | null {
|
): SelectorResolution | null {
|
||||||
if (!subBlock.selectorKey) return null
|
if (!subBlock.selectorKey) return null
|
||||||
return {
|
return {
|
||||||
key: subBlock.selectorKey,
|
key: subBlock.selectorKey,
|
||||||
context: {
|
context: {
|
||||||
workflowId: args.workflowId,
|
...context,
|
||||||
credentialId: args.credentialId,
|
mimeType: subBlock.mimeType ?? context.mimeType,
|
||||||
domain: args.domain,
|
|
||||||
projectId: args.projectId,
|
|
||||||
planId: args.planId,
|
|
||||||
teamId: args.teamId,
|
|
||||||
knowledgeBaseId: args.knowledgeBaseId,
|
|
||||||
siteId: args.siteId,
|
|
||||||
collectionId: args.collectionId,
|
|
||||||
spreadsheetId: args.spreadsheetId,
|
|
||||||
fileId: args.fileId,
|
|
||||||
baseId: args.baseId,
|
|
||||||
datasetId: args.datasetId,
|
|
||||||
serviceDeskId: args.serviceDeskId,
|
|
||||||
mimeType: subBlock.mimeType,
|
|
||||||
},
|
},
|
||||||
allowSearch: subBlock.selectorAllowSearch ?? true,
|
allowSearch: subBlock.selectorAllowSearch ?? true,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export interface SelectorOption {
|
|||||||
export interface SelectorContext {
|
export interface SelectorContext {
|
||||||
workspaceId?: string
|
workspaceId?: string
|
||||||
workflowId?: string
|
workflowId?: string
|
||||||
credentialId?: string
|
oauthCredential?: string
|
||||||
serviceId?: string
|
serviceId?: string
|
||||||
domain?: string
|
domain?: string
|
||||||
teamId?: string
|
teamId?: string
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ interface SelectorDisplayNameArgs {
|
|||||||
subBlock?: SubBlockConfig
|
subBlock?: SubBlockConfig
|
||||||
value: unknown
|
value: unknown
|
||||||
workflowId?: string
|
workflowId?: string
|
||||||
credentialId?: string
|
oauthCredential?: string
|
||||||
domain?: string
|
domain?: string
|
||||||
projectId?: string
|
projectId?: string
|
||||||
planId?: string
|
planId?: string
|
||||||
@@ -31,7 +31,7 @@ export function useSelectorDisplayName({
|
|||||||
subBlock,
|
subBlock,
|
||||||
value,
|
value,
|
||||||
workflowId,
|
workflowId,
|
||||||
credentialId,
|
oauthCredential,
|
||||||
domain,
|
domain,
|
||||||
projectId,
|
projectId,
|
||||||
planId,
|
planId,
|
||||||
@@ -51,7 +51,7 @@ export function useSelectorDisplayName({
|
|||||||
if (!subBlock || !detailId) return null
|
if (!subBlock || !detailId) return null
|
||||||
return resolveSelectorForSubBlock(subBlock, {
|
return resolveSelectorForSubBlock(subBlock, {
|
||||||
workflowId,
|
workflowId,
|
||||||
credentialId,
|
oauthCredential,
|
||||||
domain,
|
domain,
|
||||||
projectId,
|
projectId,
|
||||||
planId,
|
planId,
|
||||||
@@ -69,7 +69,7 @@ export function useSelectorDisplayName({
|
|||||||
subBlock,
|
subBlock,
|
||||||
detailId,
|
detailId,
|
||||||
workflowId,
|
workflowId,
|
||||||
credentialId,
|
oauthCredential,
|
||||||
domain,
|
domain,
|
||||||
projectId,
|
projectId,
|
||||||
planId,
|
planId,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { createLogger } from '@sim/logger'
|
import { createLogger } from '@sim/logger'
|
||||||
|
import { buildSelectorContextFromBlock } from '@/lib/workflows/subblocks/context'
|
||||||
import { getBlock } from '@/blocks/registry'
|
import { getBlock } from '@/blocks/registry'
|
||||||
import { SELECTOR_TYPES_HYDRATION_REQUIRED, type SubBlockConfig } from '@/blocks/types'
|
import { SELECTOR_TYPES_HYDRATION_REQUIRED, type SubBlockConfig } from '@/blocks/types'
|
||||||
import { CREDENTIAL_SET, isUuid } from '@/executor/constants'
|
import { CREDENTIAL_SET, isUuid } from '@/executor/constants'
|
||||||
@@ -6,7 +7,7 @@ import { fetchCredentialSetById } from '@/hooks/queries/credential-sets'
|
|||||||
import { fetchOAuthCredentialDetail } from '@/hooks/queries/oauth-credentials'
|
import { fetchOAuthCredentialDetail } from '@/hooks/queries/oauth-credentials'
|
||||||
import { getSelectorDefinition } from '@/hooks/selectors/registry'
|
import { getSelectorDefinition } from '@/hooks/selectors/registry'
|
||||||
import { resolveSelectorForSubBlock } from '@/hooks/selectors/resolution'
|
import { resolveSelectorForSubBlock } from '@/hooks/selectors/resolution'
|
||||||
import type { SelectorKey } from '@/hooks/selectors/types'
|
import type { SelectorContext, SelectorKey } from '@/hooks/selectors/types'
|
||||||
import type { WorkflowState } from '@/stores/workflows/workflow/types'
|
import type { WorkflowState } from '@/stores/workflows/workflow/types'
|
||||||
|
|
||||||
const logger = createLogger('ResolveValues')
|
const logger = createLogger('ResolveValues')
|
||||||
@@ -39,74 +40,8 @@ interface ResolutionContext {
|
|||||||
blockId?: string
|
blockId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function getSemanticFallback(subBlockConfig: SubBlockConfig): string {
|
||||||
* Extended context extracted from block subBlocks for selector resolution
|
return (subBlockConfig.title ?? subBlockConfig.id).toLowerCase()
|
||||||
*/
|
|
||||||
interface ExtendedSelectorContext {
|
|
||||||
credentialId?: string
|
|
||||||
domain?: string
|
|
||||||
projectId?: string
|
|
||||||
planId?: string
|
|
||||||
teamId?: string
|
|
||||||
knowledgeBaseId?: string
|
|
||||||
siteId?: string
|
|
||||||
collectionId?: string
|
|
||||||
spreadsheetId?: string
|
|
||||||
baseId?: string
|
|
||||||
datasetId?: string
|
|
||||||
serviceDeskId?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSemanticFallback(subBlockId: string, subBlockConfig?: SubBlockConfig): string {
|
|
||||||
if (subBlockConfig?.title) {
|
|
||||||
return subBlockConfig.title.toLowerCase()
|
|
||||||
}
|
|
||||||
|
|
||||||
const patterns: Record<string, string> = {
|
|
||||||
credential: 'credential',
|
|
||||||
channel: 'channel',
|
|
||||||
channelId: 'channel',
|
|
||||||
user: 'user',
|
|
||||||
userId: 'user',
|
|
||||||
workflow: 'workflow',
|
|
||||||
workflowId: 'workflow',
|
|
||||||
file: 'file',
|
|
||||||
fileId: 'file',
|
|
||||||
folder: 'folder',
|
|
||||||
folderId: 'folder',
|
|
||||||
project: 'project',
|
|
||||||
projectId: 'project',
|
|
||||||
team: 'team',
|
|
||||||
teamId: 'team',
|
|
||||||
sheet: 'sheet',
|
|
||||||
sheetId: 'sheet',
|
|
||||||
document: 'document',
|
|
||||||
documentId: 'document',
|
|
||||||
knowledgeBase: 'knowledge base',
|
|
||||||
knowledgeBaseId: 'knowledge base',
|
|
||||||
server: 'server',
|
|
||||||
serverId: 'server',
|
|
||||||
tool: 'tool',
|
|
||||||
toolId: 'tool',
|
|
||||||
calendar: 'calendar',
|
|
||||||
calendarId: 'calendar',
|
|
||||||
label: 'label',
|
|
||||||
labelId: 'label',
|
|
||||||
site: 'site',
|
|
||||||
siteId: 'site',
|
|
||||||
collection: 'collection',
|
|
||||||
collectionId: 'collection',
|
|
||||||
item: 'item',
|
|
||||||
itemId: 'item',
|
|
||||||
contact: 'contact',
|
|
||||||
contactId: 'contact',
|
|
||||||
task: 'task',
|
|
||||||
taskId: 'task',
|
|
||||||
chat: 'chat',
|
|
||||||
chatId: 'chat',
|
|
||||||
}
|
|
||||||
|
|
||||||
return patterns[subBlockId] || 'value'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveCredential(credentialId: string, workflowId: string): Promise<string | null> {
|
async function resolveCredential(credentialId: string, workflowId: string): Promise<string | null> {
|
||||||
@@ -150,26 +85,10 @@ async function resolveWorkflow(workflowId: string): Promise<string | null> {
|
|||||||
async function resolveSelectorValue(
|
async function resolveSelectorValue(
|
||||||
value: string,
|
value: string,
|
||||||
selectorKey: SelectorKey,
|
selectorKey: SelectorKey,
|
||||||
extendedContext: ExtendedSelectorContext,
|
selectorContext: SelectorContext
|
||||||
workflowId: string
|
|
||||||
): Promise<string | null> {
|
): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
const definition = getSelectorDefinition(selectorKey)
|
const definition = getSelectorDefinition(selectorKey)
|
||||||
const selectorContext = {
|
|
||||||
workflowId,
|
|
||||||
credentialId: extendedContext.credentialId,
|
|
||||||
domain: extendedContext.domain,
|
|
||||||
projectId: extendedContext.projectId,
|
|
||||||
planId: extendedContext.planId,
|
|
||||||
teamId: extendedContext.teamId,
|
|
||||||
knowledgeBaseId: extendedContext.knowledgeBaseId,
|
|
||||||
siteId: extendedContext.siteId,
|
|
||||||
collectionId: extendedContext.collectionId,
|
|
||||||
spreadsheetId: extendedContext.spreadsheetId,
|
|
||||||
baseId: extendedContext.baseId,
|
|
||||||
datasetId: extendedContext.datasetId,
|
|
||||||
serviceDeskId: extendedContext.serviceDeskId,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (definition.fetchById) {
|
if (definition.fetchById) {
|
||||||
const result = await definition.fetchById({
|
const result = await definition.fetchById({
|
||||||
@@ -219,37 +138,14 @@ export function formatValueForDisplay(value: unknown): string {
|
|||||||
return String(value)
|
return String(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
function extractSelectorContext(
|
||||||
* Extracts extended context from a block's subBlocks for selector resolution.
|
|
||||||
* This mirrors the context extraction done in the UI components.
|
|
||||||
*/
|
|
||||||
function extractExtendedContext(
|
|
||||||
blockId: string,
|
blockId: string,
|
||||||
currentState: WorkflowState
|
currentState: WorkflowState,
|
||||||
): ExtendedSelectorContext {
|
workflowId: string
|
||||||
|
): SelectorContext {
|
||||||
const block = currentState.blocks?.[blockId]
|
const block = currentState.blocks?.[blockId]
|
||||||
if (!block?.subBlocks) return {}
|
if (!block?.subBlocks) return { workflowId }
|
||||||
|
return buildSelectorContextFromBlock(block.type, block.subBlocks, { workflowId })
|
||||||
const getStringValue = (id: string): string | undefined => {
|
|
||||||
const subBlock = block.subBlocks[id] as { value?: unknown } | undefined
|
|
||||||
const val = subBlock?.value
|
|
||||||
return typeof val === 'string' ? val : undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
credentialId: getStringValue('credential'),
|
|
||||||
domain: getStringValue('domain'),
|
|
||||||
projectId: getStringValue('projectId'),
|
|
||||||
planId: getStringValue('planId'),
|
|
||||||
teamId: getStringValue('teamId'),
|
|
||||||
knowledgeBaseId: getStringValue('knowledgeBaseId'),
|
|
||||||
siteId: getStringValue('siteId'),
|
|
||||||
collectionId: getStringValue('collectionId'),
|
|
||||||
spreadsheetId: getStringValue('spreadsheetId') || getStringValue('fileId'),
|
|
||||||
baseId: getStringValue('baseId') || getStringValue('baseSelector'),
|
|
||||||
datasetId: getStringValue('datasetId') || getStringValue('datasetSelector'),
|
|
||||||
serviceDeskId: getStringValue('serviceDeskId') || getStringValue('serviceDeskSelector'),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -275,11 +171,14 @@ export async function resolveValueForDisplay(
|
|||||||
|
|
||||||
const blockConfig = getBlock(context.blockType)
|
const blockConfig = getBlock(context.blockType)
|
||||||
const subBlockConfig = blockConfig?.subBlocks.find((sb) => sb.id === context.subBlockId)
|
const subBlockConfig = blockConfig?.subBlocks.find((sb) => sb.id === context.subBlockId)
|
||||||
const semanticFallback = getSemanticFallback(context.subBlockId, subBlockConfig)
|
if (!subBlockConfig) {
|
||||||
|
return { original: value, displayLabel: formatValueForDisplay(value), resolved: false }
|
||||||
|
}
|
||||||
|
const semanticFallback = getSemanticFallback(subBlockConfig)
|
||||||
|
|
||||||
const extendedContext = context.blockId
|
const selectorCtx = context.blockId
|
||||||
? extractExtendedContext(context.blockId, context.currentState)
|
? extractSelectorContext(context.blockId, context.currentState, context.workflowId)
|
||||||
: {}
|
: { workflowId: context.workflowId }
|
||||||
|
|
||||||
// Credential fields (oauth-input or credential subBlockId)
|
// Credential fields (oauth-input or credential subBlockId)
|
||||||
const isCredentialField =
|
const isCredentialField =
|
||||||
@@ -311,29 +210,10 @@ export async function resolveValueForDisplay(
|
|||||||
// Selector types that require hydration (file-selector, sheet-selector, etc.)
|
// Selector types that require hydration (file-selector, sheet-selector, etc.)
|
||||||
// These support external service IDs like Google Drive file IDs
|
// These support external service IDs like Google Drive file IDs
|
||||||
if (subBlockConfig && SELECTOR_TYPES_HYDRATION_REQUIRED.includes(subBlockConfig.type)) {
|
if (subBlockConfig && SELECTOR_TYPES_HYDRATION_REQUIRED.includes(subBlockConfig.type)) {
|
||||||
const resolution = resolveSelectorForSubBlock(subBlockConfig, {
|
const resolution = resolveSelectorForSubBlock(subBlockConfig, selectorCtx)
|
||||||
workflowId: context.workflowId,
|
|
||||||
credentialId: extendedContext.credentialId,
|
|
||||||
domain: extendedContext.domain,
|
|
||||||
projectId: extendedContext.projectId,
|
|
||||||
planId: extendedContext.planId,
|
|
||||||
teamId: extendedContext.teamId,
|
|
||||||
knowledgeBaseId: extendedContext.knowledgeBaseId,
|
|
||||||
siteId: extendedContext.siteId,
|
|
||||||
collectionId: extendedContext.collectionId,
|
|
||||||
spreadsheetId: extendedContext.spreadsheetId,
|
|
||||||
baseId: extendedContext.baseId,
|
|
||||||
datasetId: extendedContext.datasetId,
|
|
||||||
serviceDeskId: extendedContext.serviceDeskId,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (resolution?.key) {
|
if (resolution?.key) {
|
||||||
const label = await resolveSelectorValue(
|
const label = await resolveSelectorValue(value, resolution.key, selectorCtx)
|
||||||
value,
|
|
||||||
resolution.key,
|
|
||||||
extendedContext,
|
|
||||||
context.workflowId
|
|
||||||
)
|
|
||||||
if (label) {
|
if (label) {
|
||||||
return { original: value, displayLabel: label, resolved: true }
|
return { original: value, displayLabel: label, resolved: true }
|
||||||
}
|
}
|
||||||
|
|||||||
125
apps/sim/lib/workflows/subblocks/context.test.ts
Normal file
125
apps/sim/lib/workflows/subblocks/context.test.ts
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
* @vitest-environment node
|
||||||
|
*/
|
||||||
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
|
|
||||||
|
vi.unmock('@/blocks/registry')
|
||||||
|
|
||||||
|
import { getAllBlocks } from '@/blocks/registry'
|
||||||
|
import { buildSelectorContextFromBlock, SELECTOR_CONTEXT_FIELDS } from './context'
|
||||||
|
import { buildCanonicalIndex, isCanonicalPair } from './visibility'
|
||||||
|
|
||||||
|
describe('buildSelectorContextFromBlock', () => {
|
||||||
|
it('should extract knowledgeBaseId from knowledgeBaseSelector via canonical mapping', () => {
|
||||||
|
const ctx = buildSelectorContextFromBlock('knowledge', {
|
||||||
|
operation: { id: 'operation', type: 'dropdown', value: 'search' },
|
||||||
|
knowledgeBaseSelector: {
|
||||||
|
id: 'knowledgeBaseSelector',
|
||||||
|
type: 'knowledge-base-selector',
|
||||||
|
value: 'kb-uuid-123',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ctx.knowledgeBaseId).toBe('kb-uuid-123')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should extract knowledgeBaseId from manualKnowledgeBaseId via canonical mapping', () => {
|
||||||
|
const ctx = buildSelectorContextFromBlock('knowledge', {
|
||||||
|
operation: { id: 'operation', type: 'dropdown', value: 'search' },
|
||||||
|
manualKnowledgeBaseId: {
|
||||||
|
id: 'manualKnowledgeBaseId',
|
||||||
|
type: 'short-input',
|
||||||
|
value: 'manual-kb-id',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ctx.knowledgeBaseId).toBe('manual-kb-id')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should skip null/empty values', () => {
|
||||||
|
const ctx = buildSelectorContextFromBlock('knowledge', {
|
||||||
|
knowledgeBaseSelector: {
|
||||||
|
id: 'knowledgeBaseSelector',
|
||||||
|
type: 'knowledge-base-selector',
|
||||||
|
value: '',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ctx.knowledgeBaseId).toBeUndefined()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should return empty context for unknown block types', () => {
|
||||||
|
const ctx = buildSelectorContextFromBlock('nonexistent_block', {
|
||||||
|
foo: { id: 'foo', type: 'short-input', value: 'bar' },
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(ctx).toEqual({})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should pass through workflowId from opts', () => {
|
||||||
|
const ctx = buildSelectorContextFromBlock(
|
||||||
|
'knowledge',
|
||||||
|
{ operation: { id: 'operation', type: 'dropdown', value: 'search' } },
|
||||||
|
{ workflowId: 'wf-123' }
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(ctx.workflowId).toBe('wf-123')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should ignore subblock keys not in SELECTOR_CONTEXT_FIELDS', () => {
|
||||||
|
const ctx = buildSelectorContextFromBlock('knowledge', {
|
||||||
|
operation: { id: 'operation', type: 'dropdown', value: 'search' },
|
||||||
|
query: { id: 'query', type: 'short-input', value: 'some search query' },
|
||||||
|
})
|
||||||
|
|
||||||
|
expect((ctx as Record<string, unknown>).query).toBeUndefined()
|
||||||
|
expect((ctx as Record<string, unknown>).operation).toBeUndefined()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('SELECTOR_CONTEXT_FIELDS validation', () => {
|
||||||
|
it('every entry must be a canonicalParamId (if a canonical pair exists) or a direct subblock ID', () => {
|
||||||
|
const allCanonicalParamIds = new Set<string>()
|
||||||
|
const allSubBlockIds = new Set<string>()
|
||||||
|
const idsInCanonicalPairs = new Set<string>()
|
||||||
|
|
||||||
|
for (const block of getAllBlocks()) {
|
||||||
|
const index = buildCanonicalIndex(block.subBlocks)
|
||||||
|
|
||||||
|
for (const sb of block.subBlocks) {
|
||||||
|
allSubBlockIds.add(sb.id)
|
||||||
|
if (sb.canonicalParamId) {
|
||||||
|
allCanonicalParamIds.add(sb.canonicalParamId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const group of Object.values(index.groupsById)) {
|
||||||
|
if (!isCanonicalPair(group)) continue
|
||||||
|
if (group.basicId) idsInCanonicalPairs.add(group.basicId)
|
||||||
|
for (const advId of group.advancedIds) idsInCanonicalPairs.add(advId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const errors: string[] = []
|
||||||
|
|
||||||
|
for (const field of SELECTOR_CONTEXT_FIELDS) {
|
||||||
|
const f = field as string
|
||||||
|
if (allCanonicalParamIds.has(f)) continue
|
||||||
|
|
||||||
|
if (idsInCanonicalPairs.has(f)) {
|
||||||
|
errors.push(
|
||||||
|
`"${f}" is a member subblock ID inside a canonical pair — use the canonicalParamId instead`
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allSubBlockIds.has(f)) {
|
||||||
|
errors.push(`"${f}" is not a canonicalParamId or subblock ID in any block definition`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw new Error(`SELECTOR_CONTEXT_FIELDS validation failed:\n${errors.join('\n')}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
60
apps/sim/lib/workflows/subblocks/context.ts
Normal file
60
apps/sim/lib/workflows/subblocks/context.ts
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import { getBlock } from '@/blocks'
|
||||||
|
import type { SelectorContext } from '@/hooks/selectors/types'
|
||||||
|
import type { SubBlockState } from '@/stores/workflows/workflow/types'
|
||||||
|
import { buildCanonicalIndex } from './visibility'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Canonical param IDs (or raw subblock IDs) that correspond to SelectorContext fields.
|
||||||
|
* A subblock's resolved canonical key is set on the context only if it appears here.
|
||||||
|
*/
|
||||||
|
export const SELECTOR_CONTEXT_FIELDS = new Set<keyof SelectorContext>([
|
||||||
|
'oauthCredential',
|
||||||
|
'domain',
|
||||||
|
'teamId',
|
||||||
|
'projectId',
|
||||||
|
'knowledgeBaseId',
|
||||||
|
'planId',
|
||||||
|
'siteId',
|
||||||
|
'collectionId',
|
||||||
|
'spreadsheetId',
|
||||||
|
'fileId',
|
||||||
|
'baseId',
|
||||||
|
'datasetId',
|
||||||
|
'serviceDeskId',
|
||||||
|
])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a SelectorContext from a block's subBlocks using the canonical index.
|
||||||
|
*
|
||||||
|
* Iterates all subblocks, resolves each through canonicalIdBySubBlockId to get
|
||||||
|
* the canonical key, then checks it against SELECTOR_CONTEXT_FIELDS.
|
||||||
|
* This avoids hardcoding subblock IDs and automatically handles basic/advanced
|
||||||
|
* renames.
|
||||||
|
*/
|
||||||
|
export function buildSelectorContextFromBlock(
|
||||||
|
blockType: string,
|
||||||
|
subBlocks: Record<string, SubBlockState | { value?: unknown }>,
|
||||||
|
opts?: { workflowId?: string }
|
||||||
|
): SelectorContext {
|
||||||
|
const context: SelectorContext = {}
|
||||||
|
if (opts?.workflowId) context.workflowId = opts.workflowId
|
||||||
|
|
||||||
|
const blockConfig = getBlock(blockType)
|
||||||
|
if (!blockConfig) return context
|
||||||
|
|
||||||
|
const canonicalIndex = buildCanonicalIndex(blockConfig.subBlocks)
|
||||||
|
|
||||||
|
for (const [subBlockId, subBlock] of Object.entries(subBlocks)) {
|
||||||
|
const val = subBlock?.value
|
||||||
|
if (val === null || val === undefined) continue
|
||||||
|
const strValue = typeof val === 'string' ? val : String(val)
|
||||||
|
if (!strValue) continue
|
||||||
|
|
||||||
|
const canonicalKey = canonicalIndex.canonicalIdBySubBlockId[subBlockId] ?? subBlockId
|
||||||
|
if (SELECTOR_CONTEXT_FIELDS.has(canonicalKey as keyof SelectorContext)) {
|
||||||
|
context[canonicalKey as keyof SelectorContext] = strValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user