Skip to content

Commit aa864d5

Browse files
committed
resource resolver
1 parent 3ada406 commit aa864d5

5 files changed

Lines changed: 98 additions & 37 deletions

File tree

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1050,13 +1050,12 @@ export function DeployModal({
10501050

10511051
interface StatusBadgeProps {
10521052
isWarning: boolean
1053-
isSyncing?: boolean
10541053
}
10551054

1056-
function StatusBadge({ isWarning, isSyncing = false }: StatusBadgeProps) {
1057-
const label = isSyncing ? 'Syncing changes' : isWarning ? 'Update deployment' : 'Live'
1055+
function StatusBadge({ isWarning }: StatusBadgeProps) {
1056+
const label = isWarning ? 'Update deployment' : 'Live'
10581057
return (
1059-
<Badge variant={isSyncing || isWarning ? 'amber' : 'green'} size='lg' dot>
1058+
<Badge variant={isWarning ? 'amber' : 'green'} size='lg' dot>
10601059
{label}
10611060
</Badge>
10621061
)
@@ -1111,7 +1110,7 @@ function GeneralFooter({
11111110
const isDeployBlocked =
11121111
deployReadiness.isBlocked || isDeploymentSettling || isSubmitting || isUndeploying
11131112
const blockedMessage =
1114-
deployReadiness.isBlocked && !isDeploymentSettling && !isSubmitting && !isUndeploying
1113+
deployReadiness.isBlocked && !deployReadiness.isSyncing && !isSubmitting && !isUndeploying
11151114
? deployReadiness.tooltip
11161115
: null
11171116
const deployActionLoading = isSubmitting || isDeploymentSettling
@@ -1133,7 +1132,7 @@ function GeneralFooter({
11331132
return (
11341133
<ModalFooter className='items-center justify-between'>
11351134
<div className='flex min-w-0 flex-col gap-1'>
1136-
<StatusBadge isWarning={needsRedeployment} isSyncing={isDeploymentSettling} />
1135+
<StatusBadge isWarning={needsRedeployment} />
11371136
{blockedMessage && (
11381137
<div className='max-w-[300px] text-muted-foreground text-xs'>{blockedMessage}</div>
11391138
)}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import { useState } from 'react'
4-
import { Button, Loader, Tooltip } from '@/components/emcn'
4+
import { Button, Tooltip } from '@/components/emcn'
55
import { DeployModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal'
66
import {
77
useChangeDetection,
@@ -65,12 +65,16 @@ export function Deploy({
6565
isDeploying ||
6666
!canDeploy ||
6767
isEmpty ||
68-
isDeploymentSettling ||
69-
(!isDeployed && deployReadiness.isBlocked)
68+
(!isDeployed && deployReadiness.isBlocked && !deployReadiness.isSyncing)
7069

7170
const onDeployClick = async () => {
7271
if (disabled || !canDeploy || !activeWorkflowId) return
7372

73+
if (isDeploymentSettling) {
74+
setIsModalOpen(true)
75+
return
76+
}
77+
7478
const result = await handleDeployClick()
7579
if (result.shouldOpenModal) {
7680
setIsModalOpen(true)
@@ -106,9 +110,6 @@ export function Deploy({
106110
}
107111

108112
const getButtonLabel = () => {
109-
if (isDeployed && (changeDetected || isDeploymentSettling)) {
110-
return 'Update'
111-
}
112113
if (changeDetected) {
113114
return 'Update'
114115
}
@@ -126,18 +127,11 @@ export function Deploy({
126127
<Button
127128
className='h-[30px] gap-1.5 px-2.5'
128129
variant={
129-
isRegistryLoading || isDeploymentSettling
130-
? 'active'
131-
: changeDetected || !isDeployed
132-
? 'tertiary'
133-
: 'active'
130+
isRegistryLoading ? 'active' : changeDetected || !isDeployed ? 'tertiary' : 'active'
134131
}
135132
onClick={onDeployClick}
136133
disabled={isRegistryLoading || isDisabled}
137134
>
138-
{(isDeploying || isDeploymentSettling) && (
139-
<Loader className='h-[13px] w-[13px]' animate />
140-
)}
141135
{getButtonLabel()}
142136
</Button>
143137
</span>

apps/sim/lib/workflows/search-replace/indexer.test.ts

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,30 @@ describe('indexWorkflowSearchMatches', () => {
3434
it('does not index internal row metadata in structured subblock values', () => {
3535
const workflow = createSearchReplaceWorkflowFixture()
3636

37-
const matches = indexWorkflowSearchMatches({
37+
const rowMatches = indexWorkflowSearchMatches({
3838
workflow,
3939
query: 'row-1',
4040
mode: 'text',
4141
blockConfigs: SEARCH_REPLACE_BLOCK_CONFIGS,
4242
})
43+
workflow.blocks['api-1'].subBlocks.body.value = {
44+
filtersById: {
45+
'filter-1': {
46+
id: 'filter-2',
47+
collapsed: false,
48+
value: '',
49+
},
50+
},
51+
}
52+
const objectMatches = indexWorkflowSearchMatches({
53+
workflow,
54+
query: 'filter-2',
55+
mode: 'text',
56+
blockConfigs: SEARCH_REPLACE_BLOCK_CONFIGS,
57+
})
4358

44-
expect(matches).toEqual([])
59+
expect(rowMatches).toEqual([])
60+
expect(objectMatches).toEqual([])
4561
})
4662

4763
it('indexes non-string scalar values as searchable but not editable', () => {
@@ -210,6 +226,63 @@ describe('indexWorkflowSearchMatches', () => {
210226
).toBe(true)
211227
})
212228

229+
it('does not match opaque structured resource ids during display-label filtering', () => {
230+
const workflow = createSearchReplaceWorkflowFixture()
231+
workflow.blocks['knowledge-1'].subBlocks.knowledgeBaseIds.value = 'kb-2-opaque-id'
232+
233+
const matches = indexWorkflowSearchMatches({
234+
workflow,
235+
query: '2',
236+
mode: 'all',
237+
includeResourceMatchesWithoutQuery: true,
238+
blockConfigs: SEARCH_REPLACE_BLOCK_CONFIGS,
239+
})
240+
const knowledgeMatch = matches.find(
241+
(match) => match.kind === 'knowledge-base' && match.rawValue === 'kb-2-opaque-id'
242+
)
243+
244+
expect(knowledgeMatch).toBeDefined()
245+
expect(
246+
workflowSearchMatchMatchesQuery({ ...knowledgeMatch!, displayLabel: 'Support Articles' }, '2')
247+
).toBe(false)
248+
expect(
249+
workflowSearchMatchMatchesQuery(
250+
{ ...knowledgeMatch!, displayLabel: 'Support Articles 2' },
251+
'2'
252+
)
253+
).toBe(true)
254+
})
255+
256+
it('does not index structured resource ids as plain text matches', () => {
257+
const workflow = createSearchReplaceWorkflowFixture()
258+
workflow.blocks['knowledge-1'].subBlocks.knowledgeBaseIds.value = 'kb-2-opaque-id'
259+
260+
const matches = indexWorkflowSearchMatches({
261+
workflow,
262+
query: '2',
263+
mode: 'all',
264+
includeResourceMatchesWithoutQuery: true,
265+
blockConfigs: SEARCH_REPLACE_BLOCK_CONFIGS,
266+
})
267+
268+
expect(
269+
matches.some(
270+
(match) =>
271+
match.kind === 'text' &&
272+
match.blockId === 'knowledge-1' &&
273+
match.subBlockId === 'knowledgeBaseIds'
274+
)
275+
).toBe(false)
276+
expect(
277+
matches.some(
278+
(match) =>
279+
match.kind === 'knowledge-base' &&
280+
match.blockId === 'knowledge-1' &&
281+
match.subBlockId === 'knowledgeBaseIds'
282+
)
283+
).toBe(true)
284+
})
285+
213286
it('captures selector context for selector-backed resources', () => {
214287
const workflow = createSearchReplaceWorkflowFixture()
215288

apps/sim/lib/workflows/search-replace/indexer.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { SubBlockType } from '@sim/workflow-types/blocks'
22
import {
3+
getResourceKindForSubBlock,
34
matchesSearchText,
45
parseInlineReferences,
56
parseStructuredResourceReferences,
@@ -66,8 +67,7 @@ const STRUCTURED_METADATA_LEAF_KEYS = new Set(['id', 'collapsed'])
6667

6768
function isSearchableLeafPath(path: Array<string | number>): boolean {
6869
const lastSegment = path.at(-1)
69-
const parentSegment = path.at(-2)
70-
if (typeof parentSegment !== 'number' || typeof lastSegment !== 'string') return true
70+
if (typeof lastSegment !== 'string') return true
7171
return !STRUCTURED_METADATA_LEAF_KEYS.has(lastSegment)
7272
}
7373

@@ -254,8 +254,9 @@ export function indexWorkflowSearchMatches(
254254
subBlockId
255255
const value = subBlockState?.value
256256
const stringLeaves = getSearchableStringLeaves(value)
257+
const structuredResourceKind = getResourceKindForSubBlock(subBlockConfig)
257258

258-
if (mode !== 'resource') {
259+
if (mode !== 'resource' && !structuredResourceKind) {
259260
for (const leaf of stringLeaves) {
260261
const leafEditable = editable && typeof leaf.originalValue === 'string'
261262
addTextMatches({

apps/sim/lib/workflows/search-replace/resource-resolvers.ts

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -98,17 +98,11 @@ export function workflowSearchMatchMatchesQuery(
9898
if (match.kind === 'text') return true
9999

100100
const normalize = (value: string) => (caseSensitive ? value : value.toLowerCase())
101-
const searchable = [
102-
match.displayLabel,
103-
match.rawValue,
104-
match.searchText,
105-
match.fieldTitle,
106-
match.blockName,
107-
match.resource?.kind,
108-
match.resource?.selectorKey,
109-
]
110-
.filter(Boolean)
111-
.join(' ')
101+
const searchable =
102+
match.resource?.kind === 'workflow-reference' || match.resource?.kind === 'environment'
103+
? [match.displayLabel, match.rawValue, match.searchText, match.fieldTitle, match.blockName]
104+
: [match.displayLabel, match.fieldTitle, match.blockName]
105+
const searchableText = searchable.filter(Boolean).join(' ')
112106

113-
return normalize(searchable).includes(normalize(trimmedQuery))
107+
return normalize(searchableText).includes(normalize(trimmedQuery))
114108
}

0 commit comments

Comments
 (0)