Skip to content

Commit d0ea8cf

Browse files
fix(tables): detect resource/URL links on workflow output regardless of column type
Workflow output columns default to `json` (columnTypeForLeaf), so routing their values through the type-based formatter (a) gated chip/URL promotion behind `column.type === 'string'` — a URL produced by a json-typed output never became a chip — and (b) JSON.stringify'd plain string values, adding quotes and losing the typewriter reveal. Detect links (sim-resource chip / favicon URL) on the value string directly for workflow outputs, falling back to the plain `value` kind; plain cells keep the type-based formatting. Addresses Greptile P2 on #4806. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent f2bfa14 commit d0ea8cf

1 file changed

Lines changed: 31 additions & 28 deletions

File tree

  • apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/cell-render.tsx

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,13 @@ export function resolveCellRender({
7777
// Value wins over pending-upstream: a finished column stays finished even
7878
// while other blocks in the group are still running. An empty string is not
7979
// a value — it falls through so a completed enrichment can show "Not found".
80-
// Format the value exactly like a plain cell (resource chip / URL / JSON /
81-
// date / boolean), keeping the typewriter reveal for plain streaming text.
82-
if (!isEmpty) return resolveValueKind(value, column, currentWorkspaceId, { typewriter: true })
80+
// A value that's wholly a resource/URL string renders as a chip/link (any
81+
// column type — workflow output is free-form); otherwise the plain `value`
82+
// kind keeps the typewriter reveal for streaming text.
83+
if (!isEmpty) {
84+
const text = stringifyValue(value)
85+
return resolveLinkKind(text, currentWorkspaceId) ?? { kind: 'value', text }
86+
}
8387

8488
if (inFlight && !(groupHasBlockErrors && !blockRunning)) {
8589
// A `pending` cell whose jobId starts with `paused-` is mid-pause
@@ -105,7 +109,15 @@ export function resolveCellRender({
105109
return { kind: 'empty' }
106110
}
107111

108-
return resolveValueKind(value, column, currentWorkspaceId, { typewriter: false })
112+
if (column.type === 'boolean') return { kind: 'boolean', checked: Boolean(value) }
113+
if (isNull) return { kind: 'empty' }
114+
if (column.type === 'json') return { kind: 'json', text: JSON.stringify(value) }
115+
if (column.type === 'date') return { kind: 'date', text: String(value) }
116+
if (column.type === 'string') {
117+
const text = stringifyValue(value)
118+
return resolveLinkKind(text, currentWorkspaceId) ?? { kind: 'text', text }
119+
}
120+
return { kind: 'text', text: stringifyValue(value) }
109121
}
110122

111123
function stringifyValue(value: unknown): string {
@@ -135,31 +147,22 @@ function resolveSimResourceKind(
135147
}
136148

137149
/**
138-
* Maps a present (non-empty) cell value to its render kind based on the column
139-
* type — the shared formatter for plain cells and workflow-output value cells,
140-
* so a workflow output renders booleans, JSON, dates, resource chips and URL
141-
* links exactly like a normal cell. `typewriter` selects the plain-text
142-
* fallback: `value` (animated reveal, for streaming workflow outputs) vs `text`
143-
* (static, for plain cells).
150+
* Promotes a cell value that is wholly a resource/URL string to a chip
151+
* (in-workspace resource) or a favicon link, else null. Shared by plain string
152+
* cells and workflow-output value cells. Workflow outputs apply this regardless
153+
* of `column.type` (their type defaults to `json`, so gating on `string` would
154+
* miss URL outputs); a stringified object never matches the whole-string URL
155+
* check, so it stays JSON/text.
144156
*/
145-
function resolveValueKind(
146-
value: unknown,
147-
column: DisplayColumn,
148-
currentWorkspaceId: string | undefined,
149-
opts: { typewriter: boolean }
150-
): CellRenderKind {
151-
if (column.type === 'boolean') return { kind: 'boolean', checked: Boolean(value) }
152-
if (value === null || value === undefined) return { kind: 'empty' }
153-
if (column.type === 'json') return { kind: 'json', text: JSON.stringify(value) }
154-
if (column.type === 'date') return { kind: 'date', text: String(value) }
155-
const text = stringifyValue(value)
156-
if (column.type === 'string') {
157-
const simKind = resolveSimResourceKind(text, currentWorkspaceId)
158-
if (simKind) return simKind
159-
const urlInfo = extractUrlInfo(text)
160-
if (urlInfo) return { kind: 'url', text, href: urlInfo.href, domain: urlInfo.domain }
161-
}
162-
return opts.typewriter ? { kind: 'value', text } : { kind: 'text', text }
157+
function resolveLinkKind(
158+
text: string,
159+
currentWorkspaceId: string | undefined
160+
): Extract<CellRenderKind, { kind: 'sim-resource' } | { kind: 'url' }> | null {
161+
const simKind = resolveSimResourceKind(text, currentWorkspaceId)
162+
if (simKind) return simKind
163+
const urlInfo = extractUrlInfo(text)
164+
if (urlInfo) return { kind: 'url', text, href: urlInfo.href, domain: urlInfo.domain }
165+
return null
163166
}
164167

165168
const BARE_DOMAIN_RE = /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/

0 commit comments

Comments
 (0)