Skip to content

Commit e6a5e7f

Browse files
improvement(selectors): simplify selector context + add tests (#3453)
* improvement(selectors): simplify selectorContext + add tests * fix resolve values fallback * another workflowid pass through
1 parent a713042 commit e6a5e7f

File tree

10 files changed

+317
-256
lines changed

10 files changed

+317
-256
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-selector-setup.ts

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { useMemo } from 'react'
44
import { useParams } from 'next/navigation'
5+
import { SELECTOR_CONTEXT_FIELDS } from '@/lib/workflows/subblocks/context'
56
import type { SubBlockConfig } from '@/blocks/types'
67
import { extractEnvVarName, isEnvVarReference, isReference } from '@/executor/constants'
78
import type { SelectorContext, SelectorKey } from '@/hooks/selectors/types'
@@ -14,8 +15,7 @@ import { useDependsOnGate } from './use-depends-on-gate'
1415
*
1516
* Builds a `SelectorContext` by mapping each `dependsOn` entry through the
1617
* canonical index to its `canonicalParamId`, which maps directly to
17-
* `SelectorContext` field names (e.g. `siteId`, `teamId`, `collectionId`).
18-
* The one special case is `oauthCredential` which maps to `credentialId`.
18+
* `SelectorContext` field names (e.g. `siteId`, `teamId`, `oauthCredential`).
1919
*
2020
* @param blockId - The block containing the selector sub-block
2121
* @param subBlock - The sub-block config (must have `selectorKey` set)
@@ -70,11 +70,8 @@ export function useSelectorSetup(
7070
if (isReference(strValue)) continue
7171

7272
const canonicalParamId = canonicalIndex.canonicalIdBySubBlockId[depKey] ?? depKey
73-
74-
if (canonicalParamId === 'oauthCredential') {
75-
context.credentialId = strValue
76-
} else if (canonicalParamId in CONTEXT_FIELD_SET) {
77-
;(context as Record<string, unknown>)[canonicalParamId] = strValue
73+
if (SELECTOR_CONTEXT_FIELDS.has(canonicalParamId as keyof SelectorContext)) {
74+
context[canonicalParamId as keyof SelectorContext] = strValue
7875
}
7976
}
8077

@@ -89,19 +86,3 @@ export function useSelectorSetup(
8986
dependencyValues: resolvedDependencyValues,
9087
}
9188
}
92-
93-
const CONTEXT_FIELD_SET: Record<string, true> = {
94-
credentialId: true,
95-
domain: true,
96-
teamId: true,
97-
projectId: true,
98-
knowledgeBaseId: true,
99-
planId: true,
100-
siteId: true,
101-
collectionId: true,
102-
spreadsheetId: true,
103-
fileId: true,
104-
baseId: true,
105-
datasetId: true,
106-
serviceDeskId: true,
107-
}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/sub-block.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,9 @@ import { useWebhookManagement } from '@/hooks/use-webhook-management'
5757
const SLACK_OVERRIDES: SelectorOverrides = {
5858
transformContext: (context, deps) => {
5959
const authMethod = deps.authMethod as string
60-
const credentialId =
60+
const oauthCredential =
6161
authMethod === 'bot_token' ? String(deps.botToken ?? '') : String(deps.credential ?? '')
62-
return { ...context, credentialId }
62+
return { ...context, oauthCredential }
6363
},
6464
}
6565

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/workflow-block.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ const SubBlockRow = memo(function SubBlockRow({
578578
subBlock,
579579
value: rawValue,
580580
workflowId,
581-
credentialId: typeof credentialId === 'string' ? credentialId : undefined,
581+
oauthCredential: typeof credentialId === 'string' ? credentialId : undefined,
582582
knowledgeBaseId: typeof knowledgeBaseId === 'string' ? knowledgeBaseId : undefined,
583583
domain: domainValue,
584584
teamId: teamIdValue,

apps/sim/hooks/selectors/registry.ts

Lines changed: 103 additions & 103 deletions
Large diffs are not rendered by default.

apps/sim/hooks/selectors/resolution.ts

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,46 +7,16 @@ export interface SelectorResolution {
77
allowSearch: boolean
88
}
99

10-
export interface SelectorResolutionArgs {
11-
workflowId?: string
12-
credentialId?: string
13-
domain?: string
14-
projectId?: string
15-
planId?: string
16-
teamId?: string
17-
knowledgeBaseId?: string
18-
siteId?: string
19-
collectionId?: string
20-
spreadsheetId?: string
21-
fileId?: string
22-
baseId?: string
23-
datasetId?: string
24-
serviceDeskId?: string
25-
}
26-
2710
export function resolveSelectorForSubBlock(
2811
subBlock: SubBlockConfig,
29-
args: SelectorResolutionArgs
12+
context: SelectorContext
3013
): SelectorResolution | null {
3114
if (!subBlock.selectorKey) return null
3215
return {
3316
key: subBlock.selectorKey,
3417
context: {
35-
workflowId: args.workflowId,
36-
credentialId: args.credentialId,
37-
domain: args.domain,
38-
projectId: args.projectId,
39-
planId: args.planId,
40-
teamId: args.teamId,
41-
knowledgeBaseId: args.knowledgeBaseId,
42-
siteId: args.siteId,
43-
collectionId: args.collectionId,
44-
spreadsheetId: args.spreadsheetId,
45-
fileId: args.fileId,
46-
baseId: args.baseId,
47-
datasetId: args.datasetId,
48-
serviceDeskId: args.serviceDeskId,
49-
mimeType: subBlock.mimeType,
18+
...context,
19+
mimeType: subBlock.mimeType ?? context.mimeType,
5020
},
5121
allowSearch: subBlock.selectorAllowSearch ?? true,
5222
}

apps/sim/hooks/selectors/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ export interface SelectorOption {
6161
export interface SelectorContext {
6262
workspaceId?: string
6363
workflowId?: string
64-
credentialId?: string
64+
oauthCredential?: string
6565
serviceId?: string
6666
domain?: string
6767
teamId?: string

apps/sim/hooks/use-selector-display-name.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ interface SelectorDisplayNameArgs {
1212
subBlock?: SubBlockConfig
1313
value: unknown
1414
workflowId?: string
15-
credentialId?: string
15+
oauthCredential?: string
1616
domain?: string
1717
projectId?: string
1818
planId?: string
@@ -31,7 +31,7 @@ export function useSelectorDisplayName({
3131
subBlock,
3232
value,
3333
workflowId,
34-
credentialId,
34+
oauthCredential,
3535
domain,
3636
projectId,
3737
planId,
@@ -51,7 +51,7 @@ export function useSelectorDisplayName({
5151
if (!subBlock || !detailId) return null
5252
return resolveSelectorForSubBlock(subBlock, {
5353
workflowId,
54-
credentialId,
54+
oauthCredential,
5555
domain,
5656
projectId,
5757
planId,
@@ -69,7 +69,7 @@ export function useSelectorDisplayName({
6969
subBlock,
7070
detailId,
7171
workflowId,
72-
credentialId,
72+
oauthCredential,
7373
domain,
7474
projectId,
7575
planId,

apps/sim/lib/workflows/comparison/resolve-values.ts

Lines changed: 14 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { createLogger } from '@sim/logger'
2+
import { buildSelectorContextFromBlock } from '@/lib/workflows/subblocks/context'
23
import { getBlock } from '@/blocks/registry'
34
import { SELECTOR_TYPES_HYDRATION_REQUIRED, type SubBlockConfig } from '@/blocks/types'
45
import { CREDENTIAL_SET, isUuid } from '@/executor/constants'
56
import { fetchCredentialSetById } from '@/hooks/queries/credential-sets'
67
import { fetchOAuthCredentialDetail } from '@/hooks/queries/oauth-credentials'
78
import { getSelectorDefinition } from '@/hooks/selectors/registry'
89
import { resolveSelectorForSubBlock } from '@/hooks/selectors/resolution'
9-
import type { SelectorKey } from '@/hooks/selectors/types'
10+
import type { SelectorContext, SelectorKey } from '@/hooks/selectors/types'
1011
import type { WorkflowState } from '@/stores/workflows/workflow/types'
1112

1213
const logger = createLogger('ResolveValues')
@@ -39,24 +40,6 @@ interface ResolutionContext {
3940
blockId?: string
4041
}
4142

42-
/**
43-
* Extended context extracted from block subBlocks for selector resolution
44-
*/
45-
interface ExtendedSelectorContext {
46-
credentialId?: string
47-
domain?: string
48-
projectId?: string
49-
planId?: string
50-
teamId?: string
51-
knowledgeBaseId?: string
52-
siteId?: string
53-
collectionId?: string
54-
spreadsheetId?: string
55-
baseId?: string
56-
datasetId?: string
57-
serviceDeskId?: string
58-
}
59-
6043
function getSemanticFallback(subBlockId: string, subBlockConfig?: SubBlockConfig): string {
6144
if (subBlockConfig?.title) {
6245
return subBlockConfig.title.toLowerCase()
@@ -150,26 +133,10 @@ async function resolveWorkflow(workflowId: string): Promise<string | null> {
150133
async function resolveSelectorValue(
151134
value: string,
152135
selectorKey: SelectorKey,
153-
extendedContext: ExtendedSelectorContext,
154-
workflowId: string
136+
selectorContext: SelectorContext
155137
): Promise<string | null> {
156138
try {
157139
const definition = getSelectorDefinition(selectorKey)
158-
const selectorContext = {
159-
workflowId,
160-
credentialId: extendedContext.credentialId,
161-
domain: extendedContext.domain,
162-
projectId: extendedContext.projectId,
163-
planId: extendedContext.planId,
164-
teamId: extendedContext.teamId,
165-
knowledgeBaseId: extendedContext.knowledgeBaseId,
166-
siteId: extendedContext.siteId,
167-
collectionId: extendedContext.collectionId,
168-
spreadsheetId: extendedContext.spreadsheetId,
169-
baseId: extendedContext.baseId,
170-
datasetId: extendedContext.datasetId,
171-
serviceDeskId: extendedContext.serviceDeskId,
172-
}
173140

174141
if (definition.fetchById) {
175142
const result = await definition.fetchById({
@@ -219,37 +186,14 @@ export function formatValueForDisplay(value: unknown): string {
219186
return String(value)
220187
}
221188

222-
/**
223-
* Extracts extended context from a block's subBlocks for selector resolution.
224-
* This mirrors the context extraction done in the UI components.
225-
*/
226-
function extractExtendedContext(
189+
function extractSelectorContext(
227190
blockId: string,
228-
currentState: WorkflowState
229-
): ExtendedSelectorContext {
191+
currentState: WorkflowState,
192+
workflowId: string
193+
): SelectorContext {
230194
const block = currentState.blocks?.[blockId]
231-
if (!block?.subBlocks) return {}
232-
233-
const getStringValue = (id: string): string | undefined => {
234-
const subBlock = block.subBlocks[id] as { value?: unknown } | undefined
235-
const val = subBlock?.value
236-
return typeof val === 'string' ? val : undefined
237-
}
238-
239-
return {
240-
credentialId: getStringValue('credential'),
241-
domain: getStringValue('domain'),
242-
projectId: getStringValue('projectId'),
243-
planId: getStringValue('planId'),
244-
teamId: getStringValue('teamId'),
245-
knowledgeBaseId: getStringValue('knowledgeBaseId'),
246-
siteId: getStringValue('siteId'),
247-
collectionId: getStringValue('collectionId'),
248-
spreadsheetId: getStringValue('spreadsheetId') || getStringValue('fileId'),
249-
baseId: getStringValue('baseId') || getStringValue('baseSelector'),
250-
datasetId: getStringValue('datasetId') || getStringValue('datasetSelector'),
251-
serviceDeskId: getStringValue('serviceDeskId') || getStringValue('serviceDeskSelector'),
252-
}
195+
if (!block?.subBlocks) return { workflowId }
196+
return buildSelectorContextFromBlock(block.type, block.subBlocks, { workflowId })
253197
}
254198

255199
/**
@@ -277,9 +221,9 @@ export async function resolveValueForDisplay(
277221
const subBlockConfig = blockConfig?.subBlocks.find((sb) => sb.id === context.subBlockId)
278222
const semanticFallback = getSemanticFallback(context.subBlockId, subBlockConfig)
279223

280-
const extendedContext = context.blockId
281-
? extractExtendedContext(context.blockId, context.currentState)
282-
: {}
224+
const selectorCtx = context.blockId
225+
? extractSelectorContext(context.blockId, context.currentState, context.workflowId)
226+
: { workflowId: context.workflowId }
283227

284228
// Credential fields (oauth-input or credential subBlockId)
285229
const isCredentialField =
@@ -311,29 +255,10 @@ export async function resolveValueForDisplay(
311255
// Selector types that require hydration (file-selector, sheet-selector, etc.)
312256
// These support external service IDs like Google Drive file IDs
313257
if (subBlockConfig && SELECTOR_TYPES_HYDRATION_REQUIRED.includes(subBlockConfig.type)) {
314-
const resolution = resolveSelectorForSubBlock(subBlockConfig, {
315-
workflowId: context.workflowId,
316-
credentialId: extendedContext.credentialId,
317-
domain: extendedContext.domain,
318-
projectId: extendedContext.projectId,
319-
planId: extendedContext.planId,
320-
teamId: extendedContext.teamId,
321-
knowledgeBaseId: extendedContext.knowledgeBaseId,
322-
siteId: extendedContext.siteId,
323-
collectionId: extendedContext.collectionId,
324-
spreadsheetId: extendedContext.spreadsheetId,
325-
baseId: extendedContext.baseId,
326-
datasetId: extendedContext.datasetId,
327-
serviceDeskId: extendedContext.serviceDeskId,
328-
})
258+
const resolution = resolveSelectorForSubBlock(subBlockConfig, selectorCtx)
329259

330260
if (resolution?.key) {
331-
const label = await resolveSelectorValue(
332-
value,
333-
resolution.key,
334-
extendedContext,
335-
context.workflowId
336-
)
261+
const label = await resolveSelectorValue(value, resolution.key, selectorCtx)
337262
if (label) {
338263
return { original: value, displayLabel: label, resolved: true }
339264
}

0 commit comments

Comments
 (0)