Skip to content

Commit 3bd7a6c

Browse files
fix(sockets): add sockets event for tag / env var dropdown selections (#844)
* fix(sockets): add sockets event for tag / env var dropdown selections to be unit op * do not bypass op queue for tag selections * Update apps/sim/socket-server/handlers/subblocks.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * prevent race cond between subblock update event and tag selection * refactor * reduce debounce time to 50ms --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
1 parent 2e2be9b commit 3bd7a6c

File tree

10 files changed

+219
-44
lines changed

10 files changed

+219
-44
lines changed

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { WandPromptBar } from '@/app/workspace/[workspaceId]/w/[workflowId]/comp
1414
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value'
1515
import { useWand } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-wand'
1616
import type { GenerationType } from '@/blocks/types'
17+
import { useTagSelection } from '@/hooks/use-tag-selection'
1718
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
1819

1920
const logger = createLogger('Code')
@@ -164,6 +165,8 @@ export function Code({
164165
},
165166
})
166167

168+
const emitTagSelection = useTagSelection(blockId, subBlockId)
169+
167170
// Use preview value when in preview mode, otherwise use store value or prop value
168171
const value = isPreview ? previewValue : propValue !== undefined ? propValue : storeValue
169172

@@ -306,7 +309,7 @@ export function Code({
306309
const handleTagSelect = (newValue: string) => {
307310
if (!isPreview) {
308311
setCode(newValue)
309-
setStoreValue(newValue)
312+
emitTagSelection(newValue)
310313
}
311314
setShowTags(false)
312315
setActiveSourceBlockId(null)
@@ -319,7 +322,7 @@ export function Code({
319322
const handleEnvVarSelect = (newValue: string) => {
320323
if (!isPreview) {
321324
setCode(newValue)
322-
setStoreValue(newValue)
325+
emitTagSelection(newValue)
323326
}
324327
setShowEnvVars(false)
325328

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { createLogger } from '@/lib/logs/console/logger'
1010
import { cn } from '@/lib/utils'
1111
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value'
1212
import type { SubBlockConfig } from '@/blocks/types'
13+
import { useTagSelection } from '@/hooks/use-tag-selection'
1314

1415
const logger = createLogger('ComboBox')
1516

@@ -53,6 +54,8 @@ export function ComboBox({
5354
const [activeSourceBlockId, setActiveSourceBlockId] = useState<string | null>(null)
5455
const [highlightedIndex, setHighlightedIndex] = useState(-1)
5556

57+
const emitTagSelection = useTagSelection(blockId, subBlockId)
58+
5659
const inputRef = useRef<HTMLInputElement>(null)
5760
const overlayRef = useRef<HTMLDivElement>(null)
5861
const dropdownRef = useRef<HTMLDivElement>(null)
@@ -330,7 +333,7 @@ export function ComboBox({
330333
// Environment variable and tag selection handler
331334
const handleEnvVarSelect = (newValue: string) => {
332335
if (!isPreview) {
333-
setStoreValue(newValue)
336+
emitTagSelection(newValue)
334337
}
335338
}
336339

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

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip
1414
import { createLogger } from '@/lib/logs/console/logger'
1515
import { cn } from '@/lib/utils'
1616
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value'
17+
import { useTagSelection } from '@/hooks/use-tag-selection'
1718
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
1819

1920
const logger = createLogger('ConditionInput')
@@ -52,6 +53,9 @@ export function ConditionInput({
5253
disabled = false,
5354
}: ConditionInputProps) {
5455
const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlockId)
56+
57+
const emitTagSelection = useTagSelection(blockId, subBlockId)
58+
5559
const containerRef = useRef<HTMLDivElement>(null)
5660
const [visualLineHeights, setVisualLineHeights] = useState<{
5761
[key: string]: number[]
@@ -400,6 +404,64 @@ export function ConditionInput({
400404
)
401405
}
402406

407+
const handleTagSelectImmediate = (blockId: string, newValue: string) => {
408+
if (isPreview || disabled) return
409+
410+
setConditionalBlocks((blocks) =>
411+
blocks.map((block) =>
412+
block.id === blockId
413+
? {
414+
...block,
415+
value: newValue,
416+
showTags: false,
417+
activeSourceBlockId: null,
418+
}
419+
: block
420+
)
421+
)
422+
423+
const updatedBlocks = conditionalBlocks.map((block) =>
424+
block.id === blockId
425+
? {
426+
...block,
427+
value: newValue,
428+
showTags: false,
429+
activeSourceBlockId: null,
430+
}
431+
: block
432+
)
433+
emitTagSelection(JSON.stringify(updatedBlocks))
434+
}
435+
436+
const handleEnvVarSelectImmediate = (blockId: string, newValue: string) => {
437+
if (isPreview || disabled) return
438+
439+
setConditionalBlocks((blocks) =>
440+
blocks.map((block) =>
441+
block.id === blockId
442+
? {
443+
...block,
444+
value: newValue,
445+
showEnvVars: false,
446+
searchTerm: '',
447+
}
448+
: block
449+
)
450+
)
451+
452+
const updatedBlocks = conditionalBlocks.map((block) =>
453+
block.id === blockId
454+
? {
455+
...block,
456+
value: newValue,
457+
showEnvVars: false,
458+
searchTerm: '',
459+
}
460+
: block
461+
)
462+
emitTagSelection(JSON.stringify(updatedBlocks))
463+
}
464+
403465
// Update block titles based on position
404466
const updateBlockTitles = (blocks: ConditionalBlock[]): ConditionalBlock[] => {
405467
return blocks.map((block, index) => ({
@@ -706,7 +768,7 @@ export function ConditionInput({
706768
{block.showEnvVars && (
707769
<EnvVarDropdown
708770
visible={block.showEnvVars}
709-
onSelect={(newValue) => handleEnvVarSelect(block.id, newValue)}
771+
onSelect={(newValue) => handleEnvVarSelectImmediate(block.id, newValue)}
710772
searchTerm={block.searchTerm}
711773
inputValue={block.value}
712774
cursorPosition={block.cursorPosition}
@@ -723,7 +785,7 @@ export function ConditionInput({
723785
{block.showTags && (
724786
<TagDropdown
725787
visible={block.showTags}
726-
onSelect={(newValue) => handleTagSelect(block.id, newValue)}
788+
onSelect={(newValue) => handleTagSelectImmediate(block.id, newValue)}
727789
blockId={blockId}
728790
activeSourceBlockId={block.activeSourceBlockId}
729791
inputValue={block.value}

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

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { cn } from '@/lib/utils'
1111
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value'
1212
import type { SubBlockConfig } from '@/blocks/types'
1313
import { useKnowledgeBaseTagDefinitions } from '@/hooks/use-knowledge-base-tag-definitions'
14+
import { useTagSelection } from '@/hooks/use-tag-selection'
1415

1516
interface DocumentTagRow {
1617
id: string
@@ -47,6 +48,8 @@ export function DocumentTagEntry({
4748
// Use KB tag definitions hook to get available tags
4849
const { tagDefinitions, isLoading } = useKnowledgeBaseTagDefinitions(knowledgeBaseId)
4950

51+
const emitTagSelection = useTagSelection(blockId, subBlock.id)
52+
5053
// State for dropdown visibility - one for each row
5154
const [dropdownStates, setDropdownStates] = useState<Record<number, boolean>>({})
5255
// State for type dropdown visibility - one for each row
@@ -128,33 +131,8 @@ export function DocumentTagEntry({
128131
setStoreValue(jsonString)
129132
}
130133

131-
const handleCellChange = (rowIndex: number, column: string, value: string) => {
132-
if (isPreview || disabled) return
133-
134-
// Check if this is a new tag name that would exceed the limit
135-
if (column === 'tagName' && value.trim()) {
136-
const isExistingTag = tagDefinitions.some(
137-
(def) => def.displayName.toLowerCase() === value.toLowerCase()
138-
)
139-
140-
if (!isExistingTag) {
141-
// Count current new tags being created (excluding the current row)
142-
const currentNewTags = rows.filter(
143-
(row, idx) =>
144-
idx !== rowIndex &&
145-
row.cells.tagName?.trim() &&
146-
!tagDefinitions.some(
147-
(def) => def.displayName.toLowerCase() === row.cells.tagName.toLowerCase()
148-
)
149-
).length
150-
151-
if (tagDefinitions.length + currentNewTags >= MAX_TAG_SLOTS) {
152-
// Don't allow creating new tags if we've reached the limit
153-
return
154-
}
155-
}
156-
}
157-
134+
// Shared helper function for updating rows and generating JSON
135+
const updateRowsAndGenerateJson = (rowIndex: number, column: string, value: string) => {
158136
const updatedRows = [...rows].map((row, idx) => {
159137
if (idx === rowIndex) {
160138
const newCells = { ...row.cells, [column]: value }
@@ -177,8 +155,6 @@ export function DocumentTagEntry({
177155
return row
178156
})
179157

180-
// No auto-add rows - user will manually add them with plus button
181-
182158
// Store all rows including empty ones - don't auto-remove
183159
const dataToStore = updatedRows.map((row) => ({
184160
id: row.id,
@@ -187,10 +163,47 @@ export function DocumentTagEntry({
187163
value: row.cells.value || '',
188164
}))
189165

190-
const jsonString = dataToStore.length > 0 ? JSON.stringify(dataToStore) : ''
166+
return dataToStore.length > 0 ? JSON.stringify(dataToStore) : ''
167+
}
168+
169+
const handleCellChange = (rowIndex: number, column: string, value: string) => {
170+
if (isPreview || disabled) return
171+
172+
// Check if this is a new tag name that would exceed the limit
173+
if (column === 'tagName' && value.trim()) {
174+
const isExistingTag = tagDefinitions.some(
175+
(def) => def.displayName.toLowerCase() === value.toLowerCase()
176+
)
177+
178+
if (!isExistingTag) {
179+
// Count current new tags being created (excluding the current row)
180+
const currentNewTags = rows.filter(
181+
(row, idx) =>
182+
idx !== rowIndex &&
183+
row.cells.tagName?.trim() &&
184+
!tagDefinitions.some(
185+
(def) => def.displayName.toLowerCase() === row.cells.tagName.toLowerCase()
186+
)
187+
).length
188+
189+
if (tagDefinitions.length + currentNewTags >= MAX_TAG_SLOTS) {
190+
// Don't allow creating new tags if we've reached the limit
191+
return
192+
}
193+
}
194+
}
195+
196+
const jsonString = updateRowsAndGenerateJson(rowIndex, column, value)
191197
setStoreValue(jsonString)
192198
}
193199

200+
const handleTagDropdownSelection = (rowIndex: number, column: string, value: string) => {
201+
if (isPreview || disabled) return
202+
203+
const jsonString = updateRowsAndGenerateJson(rowIndex, column, value)
204+
emitTagSelection(jsonString)
205+
}
206+
194207
const handleAddRow = () => {
195208
if (isPreview || disabled) return
196209

@@ -520,7 +533,8 @@ export function DocumentTagEntry({
520533
<TagDropdown
521534
visible={activeTagDropdown.showTags}
522535
onSelect={(newValue) => {
523-
handleCellChange(activeTagDropdown.rowIndex, 'value', newValue)
536+
// Use immediate emission for tag dropdown selections
537+
handleTagDropdownSelection(activeTagDropdown.rowIndex, 'value', newValue)
524538
setActiveTagDropdown(null)
525539
}}
526540
blockId={blockId}

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Label } from '@/components/ui/label'
99
import { checkTagTrigger, TagDropdown } from '@/components/ui/tag-dropdown'
1010
import type { SubBlockConfig } from '@/blocks/types'
1111
import { useKnowledgeBaseTagDefinitions } from '@/hooks/use-knowledge-base-tag-definitions'
12+
import { useTagSelection } from '@/hooks/use-tag-selection'
1213
import { useSubBlockValue } from '../../hooks/use-sub-block-value'
1314

1415
interface TagFilter {
@@ -44,6 +45,9 @@ export function KnowledgeTagFilters({
4445
}: KnowledgeTagFiltersProps) {
4546
const [storeValue, setStoreValue] = useSubBlockValue<string | null>(blockId, subBlock.id)
4647

48+
// Hook for immediate tag/dropdown selections
49+
const emitTagSelection = useTagSelection(blockId, subBlock.id)
50+
4751
// Get the knowledge base ID from other sub-blocks
4852
const [knowledgeBaseIdValue] = useSubBlockValue(blockId, 'knowledgeBaseId')
4953
const knowledgeBaseId = knowledgeBaseIdValue || null
@@ -122,6 +126,30 @@ export function KnowledgeTagFilters({
122126
updateFilters(updatedFilters)
123127
}
124128

129+
const handleTagDropdownSelection = (rowIndex: number, column: string, value: string) => {
130+
if (isPreview || disabled) return
131+
132+
const updatedRows = [...rows].map((row, idx) => {
133+
if (idx === rowIndex) {
134+
return {
135+
...row,
136+
cells: { ...row.cells, [column]: value },
137+
}
138+
}
139+
return row
140+
})
141+
142+
// Convert back to TagFilter format - keep all rows, even empty ones
143+
const updatedFilters = updatedRows.map((row) => ({
144+
id: row.id,
145+
tagName: row.cells.tagName || '',
146+
tagValue: row.cells.value || '',
147+
}))
148+
149+
const jsonValue = updatedFilters.length > 0 ? JSON.stringify(updatedFilters) : null
150+
emitTagSelection(jsonValue)
151+
}
152+
125153
const handleAddRow = () => {
126154
if (isPreview || disabled) return
127155

@@ -336,7 +364,8 @@ export function KnowledgeTagFilters({
336364
<TagDropdown
337365
visible={activeTagDropdown.showTags}
338366
onSelect={(newValue) => {
339-
handleCellChange(activeTagDropdown.rowIndex, 'value', newValue)
367+
// Use immediate emission for tag dropdown selections
368+
handleTagDropdownSelection(activeTagDropdown.rowIndex, 'value', newValue)
340369
setActiveTagDropdown(null)
341370
}}
342371
blockId={blockId}

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { WandPromptBar } from '@/app/workspace/[workspaceId]/w/[workflowId]/comp
1212
import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/workflow-block/components/sub-block/hooks/use-sub-block-value'
1313
import { useWand } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-wand'
1414
import type { SubBlockConfig } from '@/blocks/types'
15+
import { useTagSelection } from '@/hooks/use-tag-selection'
1516

1617
const logger = createLogger('LongInput')
1718

@@ -79,6 +80,8 @@ export function LongInput({
7980
},
8081
})
8182

83+
const emitTagSelection = useTagSelection(blockId, subBlockId)
84+
8285
const [showEnvVars, setShowEnvVars] = useState(false)
8386
const [showTags, setShowTags] = useState(false)
8487
const [searchTerm, setSearchTerm] = useState('')
@@ -428,7 +431,7 @@ export function LongInput({
428431
if (onChange) {
429432
onChange(newValue)
430433
} else if (!isPreview) {
431-
setStoreValue(newValue)
434+
emitTagSelection(newValue)
432435
}
433436
}}
434437
searchTerm={searchTerm}
@@ -445,7 +448,7 @@ export function LongInput({
445448
if (onChange) {
446449
onChange(newValue)
447450
} else if (!isPreview) {
448-
setStoreValue(newValue)
451+
emitTagSelection(newValue)
449452
}
450453
}}
451454
blockId={blockId}

0 commit comments

Comments
 (0)