From e6fefc863ca4cecc61ab7d1c42c512792048c5cb Mon Sep 17 00:00:00 2001 From: Waleed Date: Fri, 24 Apr 2026 16:24:49 -0700 Subject: [PATCH] fix(table-block): resolve canonical tableId in filter/sort builders (#4294) The visual filter/sort builders read the selected tableId from subBlock id 'tableId', but the Table block stores it under 'tableSelector' (basic) or 'manualTableId' (advanced) via canonicalParamId. The lookup always returned null, so useTable was disabled and the column picker always showed "no options available". Adds useCanonicalSubBlockValue that resolves by canonicalParamId through the canonical index, mirroring the pattern used by dropdown dependsOn. --- .../filter-builder/filter-builder.tsx | 3 +- .../components/sort-builder/sort-builder.tsx | 3 +- .../hooks/use-canonical-sub-block-value.ts | 49 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-canonical-sub-block-value.ts diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx index 492f2f0984..f7ef31ad5c 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/filter-builder/filter-builder.tsx @@ -6,6 +6,7 @@ import type { ComboboxOption } from '@/components/emcn' import { useTableColumns } from '@/lib/table/hooks' import type { FilterRule } from '@/lib/table/query-builder/constants' import { useFilterBuilder } from '@/lib/table/query-builder/use-query-builder' +import { useCanonicalSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-canonical-sub-block-value' 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 { FilterRuleRow } from './components/filter-rule-row' @@ -40,7 +41,7 @@ export function FilterBuilder({ tableIdSubBlockId = 'tableId', }: FilterBuilderProps) { const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlockId) - const [tableIdValue] = useSubBlockValue(blockId, tableIdSubBlockId) + const tableIdValue = useCanonicalSubBlockValue(blockId, tableIdSubBlockId) const dynamicColumns = useTableColumns({ tableId: tableIdValue }) const columns = useMemo(() => { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx index 12213e0b63..b202c4a2a9 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/sort-builder/sort-builder.tsx @@ -5,6 +5,7 @@ import { generateId } from '@sim/utils/id' import type { ComboboxOption } from '@/components/emcn' import { useTableColumns } from '@/lib/table/hooks' import { SORT_DIRECTIONS, type SortRule } from '@/lib/table/query-builder/constants' +import { useCanonicalSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-canonical-sub-block-value' import { useSubBlockValue } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-sub-block-value' import { SortRuleRow } from './components/sort-rule-row' @@ -36,7 +37,7 @@ export function SortBuilder({ tableIdSubBlockId = 'tableId', }: SortBuilderProps) { const [storeValue, setStoreValue] = useSubBlockValue(blockId, subBlockId) - const [tableIdValue] = useSubBlockValue(blockId, tableIdSubBlockId) + const tableIdValue = useCanonicalSubBlockValue(blockId, tableIdSubBlockId) const dynamicColumns = useTableColumns({ tableId: tableIdValue, includeBuiltIn: true }) const columns = useMemo(() => { diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-canonical-sub-block-value.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-canonical-sub-block-value.ts new file mode 100644 index 0000000000..3cb5fc25bf --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/hooks/use-canonical-sub-block-value.ts @@ -0,0 +1,49 @@ +import { useCallback, useMemo } from 'react' +import { isEqual } from 'es-toolkit' +import { useStoreWithEqualityFn } from 'zustand/traditional' +import { buildCanonicalIndex, resolveDependencyValue } from '@/lib/workflows/subblocks/visibility' +import { getBlock } from '@/blocks/registry' +import { useWorkflowRegistry } from '@/stores/workflows/registry/store' +import { useSubBlockStore } from '@/stores/workflows/subblock/store' +import { useWorkflowStore } from '@/stores/workflows/workflow/store' + +/** + * Read a sub-block value by either its raw subBlockId or its canonicalParamId. + * + * `useSubBlockValue` only looks up the raw subBlockId. For fields that use + * `canonicalParamId` to unify basic/advanced inputs (e.g. `tableSelector` vs + * `manualTableId` both mapping to `tableId`), this hook resolves to whichever + * member of the canonical group currently holds the value. + */ +export function useCanonicalSubBlockValue( + blockId: string, + canonicalOrSubBlockId: string +): T | null { + const activeWorkflowId = useWorkflowRegistry((s) => s.activeWorkflowId) + 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 + + return useStoreWithEqualityFn( + useSubBlockStore, + useCallback( + (state) => { + if (!activeWorkflowId) return null + const blockValues = state.workflowValues[activeWorkflowId]?.[blockId] || {} + const resolved = resolveDependencyValue( + canonicalOrSubBlockId, + blockValues, + canonicalIndex, + canonicalModeOverrides + ) + return (resolved ?? null) as T | null + }, + [activeWorkflowId, blockId, canonicalOrSubBlockId, canonicalIndex, canonicalModeOverrides] + ), + (a, b) => isEqual(a, b) + ) +}