mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
improvement(selectors): make selectorKeys declarative (#3374)
* fix(webflow): resolution for selectors * remove unecessary fallback' * fix teams selector resolution * make selector keys declarative * selectors fixes
This commit is contained in:
+35
-5
@@ -2,12 +2,16 @@
|
||||
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { Tooltip } from '@/components/emcn'
|
||||
import { buildCanonicalIndex, resolveDependencyValue } from '@/lib/workflows/subblocks/visibility'
|
||||
import { SelectorCombobox } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/selector-combobox/selector-combobox'
|
||||
import { useDependsOnGate } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-depends-on-gate'
|
||||
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value'
|
||||
import { resolvePreviewContextValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/utils'
|
||||
import { getBlock } from '@/blocks/registry'
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import type { SelectorContext } from '@/hooks/selectors/types'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
|
||||
|
||||
interface DocumentSelectorProps {
|
||||
blockId: string
|
||||
@@ -28,15 +32,41 @@ export function DocumentSelector({
|
||||
previewValue,
|
||||
previewContextValues,
|
||||
}: DocumentSelectorProps) {
|
||||
const { activeWorkflowId } = useWorkflowRegistry()
|
||||
|
||||
const { finalDisabled } = useDependsOnGate(blockId, subBlock, {
|
||||
disabled,
|
||||
isPreview,
|
||||
previewContextValues,
|
||||
})
|
||||
const [knowledgeBaseIdFromStore] = useSubBlockValue(blockId, 'knowledgeBaseId')
|
||||
const knowledgeBaseIdValue = previewContextValues
|
||||
? resolvePreviewContextValue(previewContextValues.knowledgeBaseId)
|
||||
: knowledgeBaseIdFromStore
|
||||
|
||||
const blockState = useWorkflowStore((state) => state.blocks[blockId])
|
||||
const blockConfig = blockState?.type ? getBlock(blockState.type) : null
|
||||
const canonicalIndex = useMemo(
|
||||
() => buildCanonicalIndex(blockConfig?.subBlocks || []),
|
||||
[blockConfig?.subBlocks]
|
||||
)
|
||||
const canonicalModeOverrides = blockState?.data?.canonicalModes
|
||||
|
||||
const blockValues = useSubBlockStore((state) => {
|
||||
if (!activeWorkflowId) return {}
|
||||
const workflowValues = state.workflowValues[activeWorkflowId] || {}
|
||||
return (workflowValues as Record<string, Record<string, unknown>>)[blockId] || {}
|
||||
})
|
||||
|
||||
const knowledgeBaseIdValue = useMemo(
|
||||
() =>
|
||||
previewContextValues
|
||||
? resolvePreviewContextValue(previewContextValues.knowledgeBaseId)
|
||||
: resolveDependencyValue(
|
||||
'knowledgeBaseId',
|
||||
blockValues,
|
||||
canonicalIndex,
|
||||
canonicalModeOverrides
|
||||
),
|
||||
[previewContextValues, blockValues, canonicalIndex, canonicalModeOverrides]
|
||||
)
|
||||
|
||||
const normalizedKnowledgeBaseId =
|
||||
typeof knowledgeBaseIdValue === 'string' && knowledgeBaseIdValue.trim().length > 0
|
||||
? knowledgeBaseIdValue
|
||||
|
||||
+32
-4
@@ -13,15 +13,20 @@ import {
|
||||
} from '@/components/emcn'
|
||||
import { cn } from '@/lib/core/utils/cn'
|
||||
import { FIELD_TYPE_LABELS, getPlaceholderForFieldType } from '@/lib/knowledge/constants'
|
||||
import { buildCanonicalIndex, resolveDependencyValue } from '@/lib/workflows/subblocks/visibility'
|
||||
import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text'
|
||||
import { TagDropdown } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown'
|
||||
import { useSubBlockInput } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-input'
|
||||
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value'
|
||||
import { resolvePreviewContextValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/utils'
|
||||
import { useAccessibleReferencePrefixes } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-accessible-reference-prefixes'
|
||||
import { getBlock } from '@/blocks/registry'
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import { useKnowledgeBaseTagDefinitions } from '@/hooks/kb/use-knowledge-base-tag-definitions'
|
||||
import { useTagSelection } from '@/hooks/kb/use-tag-selection'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
|
||||
|
||||
interface DocumentTag {
|
||||
id: string
|
||||
@@ -60,11 +65,26 @@ export function DocumentTagEntry({
|
||||
previewValue,
|
||||
previewContextValues,
|
||||
}: DocumentTagEntryProps) {
|
||||
const { activeWorkflowId } = useWorkflowRegistry()
|
||||
const [storeValue, setStoreValue] = useSubBlockValue<string>(blockId, subBlock.id)
|
||||
const accessiblePrefixes = useAccessibleReferencePrefixes(blockId)
|
||||
const valueInputRefs = useRef<Record<string, HTMLInputElement>>({})
|
||||
const overlayRefs = useRef<Record<string, HTMLDivElement>>({})
|
||||
|
||||
const blockState = useWorkflowStore((state) => state.blocks[blockId])
|
||||
const blockConfig = blockState?.type ? getBlock(blockState.type) : null
|
||||
const canonicalIndex = useMemo(
|
||||
() => buildCanonicalIndex(blockConfig?.subBlocks || []),
|
||||
[blockConfig?.subBlocks]
|
||||
)
|
||||
const canonicalModeOverrides = blockState?.data?.canonicalModes
|
||||
|
||||
const blockValues = useSubBlockStore((state) => {
|
||||
if (!activeWorkflowId) return {}
|
||||
const workflowValues = state.workflowValues[activeWorkflowId] || {}
|
||||
return (workflowValues as Record<string, Record<string, unknown>>)[blockId] || {}
|
||||
})
|
||||
|
||||
const inputController = useSubBlockInput({
|
||||
blockId,
|
||||
subBlockId: subBlock.id,
|
||||
@@ -77,10 +97,18 @@ export function DocumentTagEntry({
|
||||
disabled,
|
||||
})
|
||||
|
||||
const [knowledgeBaseIdFromStore] = useSubBlockValue(blockId, 'knowledgeBaseId')
|
||||
const knowledgeBaseIdValue = previewContextValues
|
||||
? resolvePreviewContextValue(previewContextValues.knowledgeBaseId)
|
||||
: knowledgeBaseIdFromStore
|
||||
const knowledgeBaseIdValue = useMemo(
|
||||
() =>
|
||||
previewContextValues
|
||||
? resolvePreviewContextValue(previewContextValues.knowledgeBaseId)
|
||||
: resolveDependencyValue(
|
||||
'knowledgeBaseId',
|
||||
blockValues,
|
||||
canonicalIndex,
|
||||
canonicalModeOverrides
|
||||
),
|
||||
[previewContextValues, blockValues, canonicalIndex, canonicalModeOverrides]
|
||||
)
|
||||
const knowledgeBaseId =
|
||||
typeof knowledgeBaseIdValue === 'string' && knowledgeBaseIdValue.trim().length > 0
|
||||
? knowledgeBaseIdValue
|
||||
|
||||
+33
-5
@@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useRef } from 'react'
|
||||
import { useMemo, useRef } from 'react'
|
||||
import { Plus } from 'lucide-react'
|
||||
import {
|
||||
Badge,
|
||||
@@ -14,14 +14,19 @@ import {
|
||||
import { cn } from '@/lib/core/utils/cn'
|
||||
import { FIELD_TYPE_LABELS, getPlaceholderForFieldType } from '@/lib/knowledge/constants'
|
||||
import { type FilterFieldType, getOperatorsForFieldType } from '@/lib/knowledge/filters/types'
|
||||
import { buildCanonicalIndex, resolveDependencyValue } from '@/lib/workflows/subblocks/visibility'
|
||||
import { formatDisplayText } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/formatted-text'
|
||||
import { TagDropdown } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown'
|
||||
import { useSubBlockInput } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-input'
|
||||
import { resolvePreviewContextValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/utils'
|
||||
import { useAccessibleReferencePrefixes } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-accessible-reference-prefixes'
|
||||
import { getBlock } from '@/blocks/registry'
|
||||
import type { SubBlockConfig } from '@/blocks/types'
|
||||
import { useKnowledgeBaseTagDefinitions } from '@/hooks/kb/use-knowledge-base-tag-definitions'
|
||||
import { useTagSelection } from '@/hooks/kb/use-tag-selection'
|
||||
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
|
||||
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
|
||||
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
|
||||
import { useSubBlockValue } from '../../hooks/use-sub-block-value'
|
||||
|
||||
interface TagFilter {
|
||||
@@ -64,15 +69,38 @@ export function KnowledgeTagFilters({
|
||||
previewValue,
|
||||
previewContextValues,
|
||||
}: KnowledgeTagFiltersProps) {
|
||||
const { activeWorkflowId } = useWorkflowRegistry()
|
||||
const [storeValue, setStoreValue] = useSubBlockValue<string | null>(blockId, subBlock.id)
|
||||
const emitTagSelection = useTagSelection(blockId, subBlock.id)
|
||||
const valueInputRefs = useRef<Record<string, HTMLInputElement>>({})
|
||||
const overlayRefs = useRef<Record<string, HTMLDivElement>>({})
|
||||
|
||||
const [knowledgeBaseIdFromStore] = useSubBlockValue(blockId, 'knowledgeBaseId')
|
||||
const knowledgeBaseIdValue = previewContextValues
|
||||
? resolvePreviewContextValue(previewContextValues.knowledgeBaseId)
|
||||
: knowledgeBaseIdFromStore
|
||||
const blockState = useWorkflowStore((state) => state.blocks[blockId])
|
||||
const blockConfig = blockState?.type ? getBlock(blockState.type) : null
|
||||
const canonicalIndex = useMemo(
|
||||
() => buildCanonicalIndex(blockConfig?.subBlocks || []),
|
||||
[blockConfig?.subBlocks]
|
||||
)
|
||||
const canonicalModeOverrides = blockState?.data?.canonicalModes
|
||||
|
||||
const blockValues = useSubBlockStore((state) => {
|
||||
if (!activeWorkflowId) return {}
|
||||
const workflowValues = state.workflowValues[activeWorkflowId] || {}
|
||||
return (workflowValues as Record<string, Record<string, unknown>>)[blockId] || {}
|
||||
})
|
||||
|
||||
const knowledgeBaseIdValue = useMemo(
|
||||
() =>
|
||||
previewContextValues
|
||||
? resolvePreviewContextValue(previewContextValues.knowledgeBaseId)
|
||||
: resolveDependencyValue(
|
||||
'knowledgeBaseId',
|
||||
blockValues,
|
||||
canonicalIndex,
|
||||
canonicalModeOverrides
|
||||
),
|
||||
[previewContextValues, blockValues, canonicalIndex, canonicalModeOverrides]
|
||||
)
|
||||
const knowledgeBaseId =
|
||||
typeof knowledgeBaseIdValue === 'string' && knowledgeBaseIdValue.trim().length > 0
|
||||
? knowledgeBaseIdValue
|
||||
|
||||
@@ -104,6 +104,7 @@ export const ConfluenceBlock: BlockConfig<ConfluenceResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'pageId',
|
||||
serviceId: 'confluence',
|
||||
selectorKey: 'confluence.pages',
|
||||
placeholder: 'Select Confluence page',
|
||||
dependsOn: ['credential', 'domain'],
|
||||
mode: 'basic',
|
||||
@@ -527,6 +528,7 @@ export const ConfluenceV2Block: BlockConfig<ConfluenceResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'pageId',
|
||||
serviceId: 'confluence',
|
||||
selectorKey: 'confluence.pages',
|
||||
placeholder: 'Select Confluence page',
|
||||
dependsOn: ['credential', 'domain'],
|
||||
mode: 'basic',
|
||||
|
||||
@@ -221,6 +221,7 @@ Return ONLY the email body - no explanations, no extra text.`,
|
||||
type: 'folder-selector',
|
||||
canonicalParamId: 'folder',
|
||||
serviceId: 'gmail',
|
||||
selectorKey: 'gmail.labels',
|
||||
requiredScopes: ['https://www.googleapis.com/auth/gmail.labels'],
|
||||
placeholder: 'Select Gmail label/folder',
|
||||
dependsOn: ['credential'],
|
||||
@@ -301,6 +302,7 @@ Return ONLY the search query - no explanations, no extra text.`,
|
||||
type: 'folder-selector',
|
||||
canonicalParamId: 'addLabelIds',
|
||||
serviceId: 'gmail',
|
||||
selectorKey: 'gmail.labels',
|
||||
requiredScopes: ['https://www.googleapis.com/auth/gmail.labels'],
|
||||
placeholder: 'Select destination label',
|
||||
dependsOn: ['credential'],
|
||||
@@ -326,6 +328,7 @@ Return ONLY the search query - no explanations, no extra text.`,
|
||||
type: 'folder-selector',
|
||||
canonicalParamId: 'removeLabelIds',
|
||||
serviceId: 'gmail',
|
||||
selectorKey: 'gmail.labels',
|
||||
requiredScopes: ['https://www.googleapis.com/auth/gmail.labels'],
|
||||
placeholder: 'Select label to remove',
|
||||
dependsOn: ['credential'],
|
||||
@@ -378,6 +381,7 @@ Return ONLY the search query - no explanations, no extra text.`,
|
||||
type: 'folder-selector',
|
||||
canonicalParamId: 'manageLabelId',
|
||||
serviceId: 'gmail',
|
||||
selectorKey: 'gmail.labels',
|
||||
requiredScopes: ['https://www.googleapis.com/auth/gmail.labels'],
|
||||
placeholder: 'Select label',
|
||||
dependsOn: ['credential'],
|
||||
|
||||
@@ -62,6 +62,8 @@ export const GoogleCalendarBlock: BlockConfig<GoogleCalendarResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'calendarId',
|
||||
serviceId: 'google-calendar',
|
||||
selectorKey: 'google.calendar',
|
||||
selectorAllowSearch: false,
|
||||
requiredScopes: ['https://www.googleapis.com/auth/calendar'],
|
||||
placeholder: 'Select calendar',
|
||||
dependsOn: ['credential'],
|
||||
@@ -326,6 +328,8 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'destinationCalendarId',
|
||||
serviceId: 'google-calendar',
|
||||
selectorKey: 'google.calendar',
|
||||
selectorAllowSearch: false,
|
||||
requiredScopes: ['https://www.googleapis.com/auth/calendar'],
|
||||
placeholder: 'Select destination calendar',
|
||||
dependsOn: ['credential'],
|
||||
|
||||
@@ -58,6 +58,7 @@ export const GoogleDocsBlock: BlockConfig<GoogleDocsResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'documentId',
|
||||
serviceId: 'google-docs',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.google-apps.document',
|
||||
placeholder: 'Select a document',
|
||||
@@ -100,6 +101,7 @@ Return ONLY the document title - no explanations, no extra text.`,
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'folderId',
|
||||
serviceId: 'google-docs',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.google-apps.folder',
|
||||
placeholder: 'Select a parent folder',
|
||||
|
||||
@@ -137,6 +137,7 @@ Return ONLY the file content - no explanations, no markdown code blocks, no extr
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'uploadFolderId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -209,6 +210,7 @@ Return ONLY the file content - no explanations, no markdown code blocks, no extr
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'createFolderParentId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -236,6 +238,7 @@ Return ONLY the file content - no explanations, no markdown code blocks, no extr
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'listFolderId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -295,6 +298,7 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'downloadFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -356,6 +360,7 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'getFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -383,6 +388,7 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'copyFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -416,6 +422,7 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'copyDestFolderId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -442,6 +449,7 @@ Return ONLY the query string - no explanations, no quotes around the whole thing
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'updateFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -520,6 +528,7 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'trashFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -547,6 +556,7 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'deleteFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -574,6 +584,7 @@ Return ONLY the description text - no explanations, no quotes, no extra text.`,
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'shareFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -688,6 +699,7 @@ Return ONLY the message text - no subject line, no greetings/signatures, no extr
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'unshareFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -723,6 +735,7 @@ Return ONLY the message text - no subject line, no greetings/signatures, no extr
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'listPermissionsFileId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
|
||||
@@ -64,6 +64,7 @@ export const GoogleFormsBlock: BlockConfig = {
|
||||
canonicalParamId: 'formId',
|
||||
required: true,
|
||||
serviceId: 'google-forms',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.google-apps.form',
|
||||
placeholder: 'Select a form',
|
||||
|
||||
@@ -62,6 +62,7 @@ export const GoogleSheetsBlock: BlockConfig<GoogleSheetsResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'google-sheets',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -360,6 +361,7 @@ export const GoogleSheetsV2Block: BlockConfig<GoogleSheetsV2Response> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'google-sheets',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [
|
||||
'https://www.googleapis.com/auth/drive.file',
|
||||
'https://www.googleapis.com/auth/drive',
|
||||
@@ -388,6 +390,8 @@ export const GoogleSheetsV2Block: BlockConfig<GoogleSheetsV2Response> = {
|
||||
type: 'sheet-selector',
|
||||
canonicalParamId: 'sheetName',
|
||||
serviceId: 'google-sheets',
|
||||
selectorKey: 'google.sheets',
|
||||
selectorAllowSearch: false,
|
||||
placeholder: 'Select a sheet',
|
||||
required: true,
|
||||
dependsOn: { all: ['credential'], any: ['spreadsheetId', 'manualSpreadsheetId'] },
|
||||
|
||||
@@ -72,6 +72,7 @@ export const GoogleSlidesBlock: BlockConfig<GoogleSlidesResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'presentationId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.google-apps.presentation',
|
||||
placeholder: 'Select a presentation',
|
||||
@@ -185,6 +186,7 @@ Return ONLY the title - no explanations, no quotes, no extra text.`,
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'folderId',
|
||||
serviceId: 'google-drive',
|
||||
selectorKey: 'google.drive',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.google-apps.folder',
|
||||
placeholder: 'Select a parent folder',
|
||||
|
||||
@@ -114,6 +114,7 @@ export const JiraBlock: BlockConfig<JiraResponse> = {
|
||||
type: 'project-selector',
|
||||
canonicalParamId: 'projectId',
|
||||
serviceId: 'jira',
|
||||
selectorKey: 'jira.projects',
|
||||
placeholder: 'Select Jira project',
|
||||
dependsOn: ['credential', 'domain'],
|
||||
mode: 'basic',
|
||||
@@ -137,6 +138,7 @@ export const JiraBlock: BlockConfig<JiraResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'issueKey',
|
||||
serviceId: 'jira',
|
||||
selectorKey: 'jira.issues',
|
||||
placeholder: 'Select Jira issue',
|
||||
dependsOn: ['credential', 'domain', 'projectId'],
|
||||
condition: {
|
||||
|
||||
@@ -75,6 +75,7 @@ export const KnowledgeBlock: BlockConfig = {
|
||||
id: 'documentId',
|
||||
title: 'Document',
|
||||
type: 'document-selector',
|
||||
selectorKey: 'knowledge.documents',
|
||||
placeholder: 'Select document',
|
||||
dependsOn: ['knowledgeBaseId'],
|
||||
required: true,
|
||||
|
||||
@@ -152,6 +152,7 @@ export const LinearBlock: BlockConfig<LinearResponse> = {
|
||||
type: 'project-selector',
|
||||
canonicalParamId: 'teamId',
|
||||
serviceId: 'linear',
|
||||
selectorKey: 'linear.teams',
|
||||
placeholder: 'Select a team',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'basic',
|
||||
@@ -228,6 +229,7 @@ export const LinearBlock: BlockConfig<LinearResponse> = {
|
||||
type: 'project-selector',
|
||||
canonicalParamId: 'projectId',
|
||||
serviceId: 'linear',
|
||||
selectorKey: 'linear.projects',
|
||||
placeholder: 'Select a project',
|
||||
dependsOn: ['credential', 'teamId'],
|
||||
mode: 'basic',
|
||||
|
||||
@@ -65,6 +65,7 @@ export const MicrosoftExcelBlock: BlockConfig<MicrosoftExcelResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'microsoft-excel',
|
||||
selectorKey: 'microsoft.excel',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
placeholder: 'Select a spreadsheet',
|
||||
@@ -392,6 +393,7 @@ export const MicrosoftExcelV2Block: BlockConfig<MicrosoftExcelV2Response> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'spreadsheetId',
|
||||
serviceId: 'microsoft-excel',
|
||||
selectorKey: 'microsoft.excel',
|
||||
requiredScopes: [],
|
||||
mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
placeholder: 'Select a spreadsheet',
|
||||
@@ -415,6 +417,8 @@ export const MicrosoftExcelV2Block: BlockConfig<MicrosoftExcelV2Response> = {
|
||||
type: 'sheet-selector',
|
||||
canonicalParamId: 'sheetName',
|
||||
serviceId: 'microsoft-excel',
|
||||
selectorKey: 'microsoft.excel.sheets',
|
||||
selectorAllowSearch: false,
|
||||
placeholder: 'Select a sheet',
|
||||
required: true,
|
||||
dependsOn: { all: ['credential'], any: ['spreadsheetId', 'manualSpreadsheetId'] },
|
||||
|
||||
@@ -108,6 +108,7 @@ export const MicrosoftPlannerBlock: BlockConfig<MicrosoftPlannerResponse> = {
|
||||
type: 'file-selector',
|
||||
placeholder: 'Select a task',
|
||||
serviceId: 'microsoft-planner',
|
||||
selectorKey: 'microsoft.planner',
|
||||
condition: { field: 'operation', value: ['read_task'] },
|
||||
dependsOn: ['credential', 'planId'],
|
||||
mode: 'basic',
|
||||
|
||||
@@ -87,6 +87,8 @@ export const MicrosoftTeamsBlock: BlockConfig<MicrosoftTeamsResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'teamId',
|
||||
serviceId: 'microsoft-teams',
|
||||
selectorKey: 'microsoft.teams',
|
||||
selectorAllowSearch: false,
|
||||
requiredScopes: [],
|
||||
placeholder: 'Select a team',
|
||||
dependsOn: ['credential'],
|
||||
@@ -132,6 +134,8 @@ export const MicrosoftTeamsBlock: BlockConfig<MicrosoftTeamsResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'chatId',
|
||||
serviceId: 'microsoft-teams',
|
||||
selectorKey: 'microsoft.chats',
|
||||
selectorAllowSearch: false,
|
||||
requiredScopes: [],
|
||||
placeholder: 'Select a chat',
|
||||
dependsOn: ['credential'],
|
||||
@@ -161,6 +165,8 @@ export const MicrosoftTeamsBlock: BlockConfig<MicrosoftTeamsResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'channelId',
|
||||
serviceId: 'microsoft-teams',
|
||||
selectorKey: 'microsoft.channels',
|
||||
selectorAllowSearch: false,
|
||||
requiredScopes: [],
|
||||
placeholder: 'Select a channel',
|
||||
dependsOn: ['credential', 'teamSelector'],
|
||||
|
||||
@@ -155,6 +155,7 @@ export const OneDriveBlock: BlockConfig<OneDriveResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'uploadFolderId',
|
||||
serviceId: 'onedrive',
|
||||
selectorKey: 'onedrive.folders',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
@@ -192,6 +193,7 @@ export const OneDriveBlock: BlockConfig<OneDriveResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'createFolderParentId',
|
||||
serviceId: 'onedrive',
|
||||
selectorKey: 'onedrive.folders',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
@@ -224,6 +226,7 @@ export const OneDriveBlock: BlockConfig<OneDriveResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'listFolderId',
|
||||
serviceId: 'onedrive',
|
||||
selectorKey: 'onedrive.folders',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
@@ -270,6 +273,7 @@ export const OneDriveBlock: BlockConfig<OneDriveResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'downloadFileId',
|
||||
serviceId: 'onedrive',
|
||||
selectorKey: 'onedrive.files',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
@@ -310,6 +314,7 @@ export const OneDriveBlock: BlockConfig<OneDriveResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'deleteFileId',
|
||||
serviceId: 'onedrive',
|
||||
selectorKey: 'onedrive.files',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
|
||||
@@ -187,6 +187,7 @@ export const OutlookBlock: BlockConfig<OutlookResponse> = {
|
||||
type: 'folder-selector',
|
||||
canonicalParamId: 'folder',
|
||||
serviceId: 'outlook',
|
||||
selectorKey: 'outlook.folders',
|
||||
requiredScopes: ['Mail.ReadWrite', 'Mail.ReadBasic', 'Mail.Read'],
|
||||
placeholder: 'Select Outlook folder',
|
||||
dependsOn: ['credential'],
|
||||
@@ -232,6 +233,7 @@ export const OutlookBlock: BlockConfig<OutlookResponse> = {
|
||||
type: 'folder-selector',
|
||||
canonicalParamId: 'destinationId',
|
||||
serviceId: 'outlook',
|
||||
selectorKey: 'outlook.folders',
|
||||
requiredScopes: ['Mail.ReadWrite', 'Mail.ReadBasic', 'Mail.Read'],
|
||||
placeholder: 'Select destination folder',
|
||||
dependsOn: ['credential'],
|
||||
@@ -278,6 +280,7 @@ export const OutlookBlock: BlockConfig<OutlookResponse> = {
|
||||
type: 'folder-selector',
|
||||
canonicalParamId: 'copyDestinationId',
|
||||
serviceId: 'outlook',
|
||||
selectorKey: 'outlook.folders',
|
||||
requiredScopes: ['Mail.ReadWrite', 'Mail.ReadBasic', 'Mail.Read'],
|
||||
placeholder: 'Select destination folder',
|
||||
dependsOn: ['credential'],
|
||||
|
||||
@@ -67,6 +67,7 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'siteId',
|
||||
serviceId: 'sharepoint',
|
||||
selectorKey: 'sharepoint.sites',
|
||||
requiredScopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
|
||||
@@ -130,6 +130,7 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
|
||||
type: 'channel-selector',
|
||||
canonicalParamId: 'channel',
|
||||
serviceId: 'slack',
|
||||
selectorKey: 'slack.channels',
|
||||
placeholder: 'Select Slack channel',
|
||||
mode: 'basic',
|
||||
dependsOn: { all: ['authMethod'], any: ['credential', 'botToken'] },
|
||||
@@ -182,6 +183,7 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
|
||||
type: 'user-selector',
|
||||
canonicalParamId: 'dmUserId',
|
||||
serviceId: 'slack',
|
||||
selectorKey: 'slack.users',
|
||||
placeholder: 'Select Slack user',
|
||||
mode: 'basic',
|
||||
dependsOn: { all: ['authMethod'], any: ['credential', 'botToken'] },
|
||||
|
||||
@@ -61,6 +61,7 @@ export const WealthboxBlock: BlockConfig<WealthboxResponse> = {
|
||||
title: 'Select Contact',
|
||||
type: 'file-selector',
|
||||
serviceId: 'wealthbox',
|
||||
selectorKey: 'wealthbox.contacts',
|
||||
requiredScopes: ['login', 'data'],
|
||||
placeholder: 'Enter Contact ID',
|
||||
mode: 'basic',
|
||||
|
||||
@@ -56,6 +56,8 @@ export const WebflowBlock: BlockConfig<WebflowResponse> = {
|
||||
type: 'project-selector',
|
||||
canonicalParamId: 'siteId',
|
||||
serviceId: 'webflow',
|
||||
selectorKey: 'webflow.sites',
|
||||
selectorAllowSearch: false,
|
||||
placeholder: 'Select Webflow site',
|
||||
dependsOn: ['credential'],
|
||||
mode: 'basic',
|
||||
@@ -76,6 +78,8 @@ export const WebflowBlock: BlockConfig<WebflowResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'collectionId',
|
||||
serviceId: 'webflow',
|
||||
selectorKey: 'webflow.collections',
|
||||
selectorAllowSearch: false,
|
||||
placeholder: 'Select collection',
|
||||
dependsOn: ['credential', 'siteSelector'],
|
||||
mode: 'basic',
|
||||
@@ -96,6 +100,7 @@ export const WebflowBlock: BlockConfig<WebflowResponse> = {
|
||||
type: 'file-selector',
|
||||
canonicalParamId: 'itemId',
|
||||
serviceId: 'webflow',
|
||||
selectorKey: 'webflow.items',
|
||||
placeholder: 'Select item',
|
||||
dependsOn: ['credential', 'collectionSelector'],
|
||||
mode: 'basic',
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { JSX, SVGProps } from 'react'
|
||||
import type { SelectorKey } from '@/hooks/selectors/types'
|
||||
import type { ToolResponse } from '@/tools/types'
|
||||
|
||||
export type BlockIcon = (props: SVGProps<SVGSVGElement>) => JSX.Element
|
||||
@@ -290,6 +291,9 @@ export interface SubBlockConfig {
|
||||
requiredScopes?: string[]
|
||||
// Whether this credential selector supports credential sets (for trigger blocks)
|
||||
supportsCredentialSets?: boolean
|
||||
// Selector properties — declarative mapping to a SelectorKey
|
||||
selectorKey?: SelectorKey
|
||||
selectorAllowSearch?: boolean
|
||||
// File selector specific properties
|
||||
mimeType?: string
|
||||
// File upload specific properties
|
||||
|
||||
@@ -20,212 +20,26 @@ export interface SelectorResolutionArgs {
|
||||
spreadsheetId?: string
|
||||
}
|
||||
|
||||
const defaultContext: SelectorContext = {}
|
||||
|
||||
export function resolveSelectorForSubBlock(
|
||||
subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution | null {
|
||||
switch (subBlock.type) {
|
||||
case 'file-selector':
|
||||
return resolveFileSelector(subBlock, args)
|
||||
case 'sheet-selector':
|
||||
return resolveSheetSelector(subBlock, args)
|
||||
case 'folder-selector':
|
||||
return resolveFolderSelector(subBlock, args)
|
||||
case 'channel-selector':
|
||||
return resolveChannelSelector(subBlock, args)
|
||||
case 'user-selector':
|
||||
return resolveUserSelector(subBlock, args)
|
||||
case 'project-selector':
|
||||
return resolveProjectSelector(subBlock, args)
|
||||
case 'document-selector':
|
||||
return resolveDocumentSelector(subBlock, args)
|
||||
default:
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function buildBaseContext(
|
||||
args: SelectorResolutionArgs,
|
||||
extra?: Partial<SelectorContext>
|
||||
): SelectorContext {
|
||||
if (!subBlock.selectorKey) return null
|
||||
return {
|
||||
...defaultContext,
|
||||
workflowId: args.workflowId,
|
||||
credentialId: args.credentialId,
|
||||
domain: args.domain,
|
||||
projectId: args.projectId,
|
||||
planId: args.planId,
|
||||
teamId: args.teamId,
|
||||
knowledgeBaseId: args.knowledgeBaseId,
|
||||
siteId: args.siteId,
|
||||
collectionId: args.collectionId,
|
||||
spreadsheetId: args.spreadsheetId,
|
||||
...extra,
|
||||
}
|
||||
}
|
||||
|
||||
function resolveFileSelector(
|
||||
subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution {
|
||||
const context = buildBaseContext(args, {
|
||||
mimeType: subBlock.mimeType,
|
||||
})
|
||||
|
||||
// Use serviceId as the canonical identifier
|
||||
const serviceId = subBlock.serviceId || ''
|
||||
|
||||
switch (serviceId) {
|
||||
case 'google-calendar':
|
||||
return { key: 'google.calendar', context, allowSearch: false }
|
||||
case 'confluence':
|
||||
return { key: 'confluence.pages', context, allowSearch: true }
|
||||
case 'jira':
|
||||
return { key: 'jira.issues', context, allowSearch: true }
|
||||
case 'microsoft-teams':
|
||||
// Route to the correct selector based on what type of resource is being selected
|
||||
if (subBlock.id === 'chatId') {
|
||||
return { key: 'microsoft.chats', context, allowSearch: false }
|
||||
}
|
||||
if (subBlock.id === 'channelId') {
|
||||
return { key: 'microsoft.channels', context, allowSearch: false }
|
||||
}
|
||||
// Default to teams selector for teamId
|
||||
return { key: 'microsoft.teams', context, allowSearch: false }
|
||||
case 'wealthbox':
|
||||
return { key: 'wealthbox.contacts', context, allowSearch: true }
|
||||
case 'microsoft-planner':
|
||||
return { key: 'microsoft.planner', context, allowSearch: true }
|
||||
case 'microsoft-excel':
|
||||
return { key: 'microsoft.excel', context, allowSearch: true }
|
||||
case 'microsoft-word':
|
||||
return { key: 'microsoft.word', context, allowSearch: true }
|
||||
case 'google-drive':
|
||||
return { key: 'google.drive', context, allowSearch: true }
|
||||
case 'google-sheets':
|
||||
return { key: 'google.drive', context, allowSearch: true }
|
||||
case 'google-docs':
|
||||
return { key: 'google.drive', context, allowSearch: true }
|
||||
case 'google-slides':
|
||||
return { key: 'google.drive', context, allowSearch: true }
|
||||
case 'google-forms':
|
||||
return { key: 'google.drive', context, allowSearch: true }
|
||||
case 'onedrive': {
|
||||
const key: SelectorKey = subBlock.mimeType === 'file' ? 'onedrive.files' : 'onedrive.folders'
|
||||
return { key, context, allowSearch: true }
|
||||
}
|
||||
case 'sharepoint':
|
||||
return { key: 'sharepoint.sites', context, allowSearch: true }
|
||||
case 'webflow':
|
||||
if (subBlock.id === 'collectionId') {
|
||||
return { key: 'webflow.collections', context, allowSearch: false }
|
||||
}
|
||||
if (subBlock.id === 'itemId') {
|
||||
return { key: 'webflow.items', context, allowSearch: true }
|
||||
}
|
||||
return { key: null, context, allowSearch: true }
|
||||
default:
|
||||
return { key: null, context, allowSearch: true }
|
||||
}
|
||||
}
|
||||
|
||||
function resolveSheetSelector(
|
||||
subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution {
|
||||
const serviceId = subBlock.serviceId
|
||||
const context = buildBaseContext(args)
|
||||
|
||||
switch (serviceId) {
|
||||
case 'google-sheets':
|
||||
return { key: 'google.sheets', context, allowSearch: false }
|
||||
case 'microsoft-excel':
|
||||
return { key: 'microsoft.excel.sheets', context, allowSearch: false }
|
||||
default:
|
||||
return { key: null, context, allowSearch: false }
|
||||
}
|
||||
}
|
||||
|
||||
function resolveFolderSelector(
|
||||
subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution {
|
||||
const serviceId = subBlock.serviceId?.toLowerCase()
|
||||
if (!serviceId) {
|
||||
return { key: null, context: buildBaseContext(args), allowSearch: true }
|
||||
}
|
||||
|
||||
switch (serviceId) {
|
||||
case 'gmail':
|
||||
return { key: 'gmail.labels', context: buildBaseContext(args), allowSearch: true }
|
||||
case 'outlook':
|
||||
return { key: 'outlook.folders', context: buildBaseContext(args), allowSearch: true }
|
||||
default:
|
||||
return { key: null, context: buildBaseContext(args), allowSearch: true }
|
||||
}
|
||||
}
|
||||
|
||||
function resolveChannelSelector(
|
||||
subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution {
|
||||
const serviceId = subBlock.serviceId
|
||||
if (serviceId !== 'slack') {
|
||||
return { key: null, context: buildBaseContext(args), allowSearch: true }
|
||||
}
|
||||
return {
|
||||
key: 'slack.channels',
|
||||
context: buildBaseContext(args),
|
||||
allowSearch: true,
|
||||
}
|
||||
}
|
||||
|
||||
function resolveUserSelector(
|
||||
subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution {
|
||||
const serviceId = subBlock.serviceId
|
||||
if (serviceId !== 'slack') {
|
||||
return { key: null, context: buildBaseContext(args), allowSearch: true }
|
||||
}
|
||||
return {
|
||||
key: 'slack.users',
|
||||
context: buildBaseContext(args),
|
||||
allowSearch: true,
|
||||
}
|
||||
}
|
||||
|
||||
function resolveProjectSelector(
|
||||
subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution {
|
||||
const serviceId = subBlock.serviceId
|
||||
const context = buildBaseContext(args)
|
||||
const selectorId = subBlock.canonicalParamId ?? subBlock.id
|
||||
|
||||
switch (serviceId) {
|
||||
case 'linear': {
|
||||
const key: SelectorKey = selectorId === 'teamId' ? 'linear.teams' : 'linear.projects'
|
||||
return { key, context, allowSearch: true }
|
||||
}
|
||||
case 'jira':
|
||||
return { key: 'jira.projects', context, allowSearch: true }
|
||||
case 'webflow':
|
||||
return { key: 'webflow.sites', context, allowSearch: false }
|
||||
default:
|
||||
return { key: null, context, allowSearch: true }
|
||||
}
|
||||
}
|
||||
|
||||
function resolveDocumentSelector(
|
||||
_subBlock: SubBlockConfig,
|
||||
args: SelectorResolutionArgs
|
||||
): SelectorResolution {
|
||||
return {
|
||||
key: 'knowledge.documents',
|
||||
context: buildBaseContext(args),
|
||||
allowSearch: true,
|
||||
key: subBlock.selectorKey,
|
||||
context: {
|
||||
workflowId: args.workflowId,
|
||||
credentialId: args.credentialId,
|
||||
domain: args.domain,
|
||||
projectId: args.projectId,
|
||||
planId: args.planId,
|
||||
teamId: args.teamId,
|
||||
knowledgeBaseId: args.knowledgeBaseId,
|
||||
siteId: args.siteId,
|
||||
collectionId: args.collectionId,
|
||||
spreadsheetId: args.spreadsheetId,
|
||||
mimeType: subBlock.mimeType,
|
||||
},
|
||||
allowSearch: subBlock.selectorAllowSearch ?? true,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user