Commit 65e2fe8
feat(tables): Add enrichment table column type (#4752)
* feat(tables): native enrichments sidebar + workflow input mapping
Add a Clay-style enrichments catalog to the table view and wire per-row
input mapping into workflow-backed columns.
- New "Enrichments" entry in the New-column dropdown opens a sliding panel
listing curated enrichment templates; picking one swaps to the workflow
config in-place (no cross-slide) with a back button.
- Type the workflow sidebar as manual | enrichment; enrichment hides the
launch + add-column-inputs affordances.
- Add a "Workflow inputs" advanced panel mapping Start-block input fields to
table columns (left-of-workflow columns only), with name-match auto-fill
and collapsible input-mapping-style rows.
- Persist type + inputMappings on the workflow group (types, contract, route,
service, hook) — jsonb, no migration.
- Consume inputMappings at run time: when present, feed Start-block fields
from the mapped columns; otherwise fall back to name-match spread.
- Clean up inputMappings on column rename/delete (stripGroupDeps + renameColumn).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(emcn): extract CollapsibleCard and reuse for input mapping
Pull the collapsible field-card markup (surface-4 header + surface-2 body,
click/keyboard toggle, truncated title + optional badge) into a shared
`CollapsibleCard` emcn component, and use it in the workflow-builder input
mapping rows and the table sidebar's input-mapping panel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(tables): code-defined enrichment registry run directly per row
Enrichments are now TS configs in apps/sim/enrichments/ (registry, like
connectors) that run directly per table row via the existing run/dispatch/
cell-write rails — no workflow execution.
- enrichments/{types,registry} + work-email (heuristic) and phone-number (stub).
- WorkflowGroup gains enrichmentId; WorkflowGroupOutput gains outputId
(workflowId/blockId/path kept required, '' for enrichment groups).
- Executor branches on group.type === 'enrichment' → maps inputMappings →
enrich() → outputs by outputId → cell-write. Missing required inputs skip
(blank cell) instead of erroring.
- Sidebar lists the registry; enrichment-config panel maps inputs to columns
and creates the enrichment group (no workflow UI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(enrichments): provider fallback cascade + hosted-key usage source
Replace each enrichment's single enrich() with an ordered providers[]
fallback cascade. Providers are plain data ({ id, label, toolId,
buildParams, mapOutput }) so the catalog stays client-safe; the
server-only runner (run.ts) calls executeTool per provider, first
non-empty result wins, misses/errors fall through, all-miss = blank cell.
Wire four enrichments on the hosted-safe providers (Hunter, PDL):
- Work Email (fullName, companyDomain): Hunter -> PDL
- Phone Number (fullName, companyDomain): PDL
- Company Domain (companyName): PDL
- Company Info (domain): PDL -> Hunter
Person enrichments take a single canonical fullName (Clay-style); Hunter
gets first/last via splitName(), PDL takes name directly.
Add 'enrichment' to usage_log_source enum (+ migration) so hosted-key
tool cost from these per-row calls can be billed to the table owner.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(enrichments): bill hosted-key cost; surface provider errors; abort safety
- runEnrichment now returns { result, cost, error }: accumulates hosted-key
cost across the cascade, and sets `error` only when every provider that ran
errored (auth/rate-limit/outage) vs a clean miss.
- Executor records the cost to the table owner (createdBy) via recordUsage
(source 'enrichment'); billing failures are logged, never error the cell.
- F1: all-providers-errored now writes status 'error' instead of a blank
'completed' cell that looked like "no data found".
- F2: re-check the abort signal after the cascade so a cancel mid-tool-call
isn't recorded as a completed empty cell.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(tables): present enrichment columns as first-class in the grid
- Meta-header shows the enrichment's name + icon (Mail/Phone/Globe/Building2)
instead of "Workflow" + a color chip.
- Per-column header icon uses the enrichment's icon (via columnSourceInfo)
instead of the generic play icon.
- Hide "View execution" for enrichment cells in both the row context menu and
the action bar (no workflow execution exists to open); also hide the
meta-menu "View workflow" item for enrichment groups.
- Clicking an enrichment column header now opens the enrichments sidebar in
edit mode (pre-filled input mappings, Update via useUpdateWorkflowGroup)
instead of the workflow "Configure workflow" sidebar.
- Enrichment config lets the user name each output column (editable per-output,
deduped defaults) since enrichments can produce multiple columns.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(tables): enrichment columns use type icon; output names editable
- Drop the per-column enrichment icon (it duplicated the meta-header icon).
Enrichment output columns now render the standard column-type icon (Text,
etc.) — the enrichment's icon stays only on the group meta-header.
- Make output column names editable in the enrichment config edit mode too;
changed names rename their columns via useUpdateColumn (the rename cascades
into the group's output refs server-side). Validation excludes the output's
own current name.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(tables): wrap enrichment catalog descriptions instead of truncating
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(tables): edit enrichment output columns via the plain column editor
Edit column on an enrichment output now opens the normal column-config sidebar
(rename / type / unique) instead of the workflow 'Configure output column'
panel, which showed workflow-only fields and blocked a simple rename.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(copilot): list_enrichments + add_enrichment table tools
Let the copilot enumerate the code-defined enrichment registry and add an
enrichment column to a table (validating required input mappings against the
table's columns), backed by the same workflow-group machinery the UI uses.
* fix(enrichments): address PR review feedback
- Guard the enrichment cell path on `enrichmentId` so a group typed
'enrichment' without a registry id falls through to the workflow path
instead of erroring.
- Clear stale output values when skipping a row for missing required inputs,
so the auto cascade re-enriches once inputs return (was left completed+filled).
- Write a terminal state on abort in the enrichment path (matches the workflow
path) so a cancel between run and terminal-write can't leave the cell running.
- Edit mode: apply the group update (mappings/deps/auto-run) before column
renames so the primary edit lands even if a rename fails.
- Disable Save once validation has surfaced a missing required input.
- Use the workflowGroupById map instead of O(n) find in the context-menu and
action-bar hot paths.
* chore(commands): add /add-enrichment command
Guides adding a code-defined table enrichment to the registry, with a required
step to verify each provider tool has hosted-key support and chain to
/add-hosted-key when it doesn't.
* fix(enrichments): address second-pass PR review
- updateWorkflowGroup output diff now keys on outputId (falling back to
blockId::path) so enrichment outputs — which share empty blockId/path —
no longer collapse to one key and drop sibling columns.
- Enrichment terminal write now clears output columns absent from the result,
so a partial/empty re-run doesn't leave stale values.
- Editing a group whose enrichment was removed from the registry shows an
explanatory panel instead of silently falling through to the new-enrichment
catalog.
* feat(tables): show "Not found" badge for empty completed enrichment cells
An enrichment that runs to completion but matches nothing now renders a gray
"Not found" badge (like the Queued/Waiting cell states) instead of a blank
cell, so a real miss is distinguishable from an unrun cell. Scoped to
enrichment output columns; an empty string no longer counts as a value.
* fix(enrichments): don't re-run completed no-match enrichments on auto cascade
A completed enrichment with empty outputs is a real no-match result, not an
unfinished run. Eligibility now treats an enrichment's completed status as
terminal (regardless of output fill), so the auto cascade stops re-invoking
billable provider calls on every no-match row each dispatch. Input changes
still clear the exec entry, so genuine re-runs are unaffected; manual Run all
still re-runs.
* fix(enrichments): treat provider 404 as no-match, not a cell error
Providers like People Data Labs signal 'no record found' with HTTP 404, which
executeTool surfaces as a failed ToolResponse (status on output.status). The
cascade now treats a 404 as a clean miss — falls through to the next provider
and lets the cell render 'Not found' — instead of marking the cell errored.
Auth/rate-limit/5xx still propagate as real errors.
* fix(tools): surface HTTP status on error ToolResponse output
executeTool's catch handled Error instances in its first branch and only
extracted status/statusText/data for non-Error object throws — so HTTP errors
(thrown as Error instances carrying .status) lost their status on the returned
output. Surface it for Error instances too, so callers can branch on the
status (e.g. the enrichment cascade treating a provider 404 as a no-match).
* fix lint
* Revert ff
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent a1aa168 commit 65e2fe8
51 files changed
Lines changed: 19593 additions & 308 deletions
File tree
- .claude/commands
- apps/sim
- app
- api/table/[tableId]/groups
- workspace/[workspaceId]
- tables/[tableId]
- components
- enrichments-sidebar
- new-column-dropdown
- table-grid
- cells
- headers
- workflow-sidebar
- hooks
- w/[workflowId]/components/panel/components/editor/components/sub-block/components/input-mapping
- background
- components/emcn/components
- collapsible-card
- enrichments
- company-domain
- company-info
- phone-number
- work-email
- hooks/queries
- lib
- api/contracts
- billing/core
- copilot
- generated
- tools/server
- table
- table
- tools
- packages/db
- migrations
- meta
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
116 | 120 | | |
117 | 121 | | |
118 | 122 | | |
| |||
0 commit comments