Skip to content

Commit 2408b4d

Browse files
Column ui improvements
1 parent 6e2f973 commit 2408b4d

11 files changed

Lines changed: 393 additions & 127 deletions

File tree

apps/sim/app/api/table/[tableId]/groups/[groupId]/run/route.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ const logger = createLogger('TableRunGroupAPI')
1717

1818
const RunSchema = z.object({
1919
workspaceId: z.string().min(1, 'Workspace ID is required'),
20+
/**
21+
* `all` — every dep-satisfied row that isn't already running/pending.
22+
* `incomplete` — same, but additionally restricted to rows whose group has
23+
* never run, or whose last run ended in `failed`/`aborted`. Used by the
24+
* "Run unrun & aborted rows" affordance in the group header.
25+
*/
26+
mode: z.enum(['all', 'incomplete']).default('all'),
2027
})
2128

2229
interface RouteParams {
@@ -95,6 +102,12 @@ export const POST = withRouteHandler(async (request: NextRequest, { params }: Ro
95102
const exec = tableRow.executions[groupId]
96103
if (exec?.status === 'running') return false
97104
if (exec?.status === 'pending' && exec?.jobId) return false
105+
if (validated.mode === 'incomplete') {
106+
// Include rows that have never run (no exec record) or whose last run
107+
// ended in `failed`/`aborted`. Skip `completed`.
108+
const status = exec?.status
109+
if (status === 'completed') return false
110+
}
98111
try {
99112
return areGroupDepsSatisfied(group, tableRow)
100113
} catch {
@@ -106,6 +119,10 @@ export const POST = withRouteHandler(async (request: NextRequest, { params }: Ro
106119
return NextResponse.json({ success: true, data: { triggered: 0 } })
107120
}
108121

122+
// Clear the group's output cells so the rerun starts visually fresh.
123+
const clearedData = Object.fromEntries(
124+
group.outputs.map((o) => [o.columnName, null])
125+
) as RowData
109126
const updates = eligibleRows.map((r) => {
110127
const pendingExec: RowExecutionMetadata = {
111128
status: 'pending',
@@ -116,7 +133,7 @@ export const POST = withRouteHandler(async (request: NextRequest, { params }: Ro
116133
}
117134
return {
118135
rowId: r.id,
119-
data: {} as RowData,
136+
data: clearedData,
120137
executionsPatch: { [groupId]: pendingExec },
121138
}
122139
})

apps/sim/app/api/table/[tableId]/rows/[rowId]/run-workflow-group/route.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,17 @@ export const POST = withRouteHandler(async (request: NextRequest, { params }: Ro
6161
workflowId: group.workflowId,
6262
error: null,
6363
}
64+
// Clear the group's output cells so the rerun starts visually fresh —
65+
// otherwise stale values from the previous run linger in the UI until the
66+
// new run writes new ones (or doesn't, on error/router-skip).
67+
const clearedData = Object.fromEntries(
68+
group.outputs.map((o) => [o.columnName, null])
69+
)
6470
await updateRow(
6571
{
6672
tableId,
6773
rowId,
68-
data: {},
74+
data: clearedData,
6975
workspaceId: validated.workspaceId,
7076
executionsPatch: { [validated.groupId]: pendingExec },
7177
},

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/column-sidebar/column-sidebar.tsx

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,26 @@ function deriveOutputColumnName(
9292

9393
const OUTPUT_VALUE_SEPARATOR = '::'
9494

95+
type ColumnType = ColumnDefinition['type']
96+
97+
/**
98+
* Map a block-output leaf type onto a table column type. Block schemas use a
99+
* superset (`array`, `object`, etc.); anything outside the column-type union
100+
* falls back to `json`, the most permissive shape that still validates.
101+
*/
102+
function columnTypeForLeaf(leafType: string | undefined): ColumnType {
103+
switch (leafType) {
104+
case 'string':
105+
case 'number':
106+
case 'boolean':
107+
case 'date':
108+
case 'json':
109+
return leafType
110+
default:
111+
return 'json'
112+
}
113+
}
114+
95115
/** Shared dashed-divider style — mirrors the workflow editor's subblock divider. */
96116
const DASHED_DIVIDER_STYLE = {
97117
backgroundImage:
@@ -509,9 +529,13 @@ export function ColumnSidebar({
509529
* state, sorted by execution order. Empty array if the user hasn't picked
510530
* anything.
511531
*/
512-
const buildOrderedPickedOutputs = (): Array<{ blockId: string; path: string }> => {
532+
const buildOrderedPickedOutputs = (): Array<{
533+
blockId: string
534+
path: string
535+
leafType?: string
536+
}> => {
513537
const seen = new Set<string>()
514-
const outputs: Array<{ blockId: string; path: string }> = []
538+
const outputs: Array<{ blockId: string; path: string; leafType?: string }> = []
515539
for (const encoded of selectedOutputs) {
516540
if (seen.has(encoded)) continue
517541
seen.add(encoded)
@@ -532,6 +556,12 @@ export function ColumnSidebar({
532556
const indexInFlat = new Map(
533557
flat.map((f, i) => [`${f.blockId}${OUTPUT_VALUE_SEPARATOR}${f.path}`, i])
534558
)
559+
const leafTypeByKey = new Map(
560+
flat.map((f) => [`${f.blockId}${OUTPUT_VALUE_SEPARATOR}${f.path}`, f.leafType])
561+
)
562+
for (const o of outputs) {
563+
o.leafType = leafTypeByKey.get(`${o.blockId}${OUTPUT_VALUE_SEPARATOR}${o.path}`)
564+
}
535565
outputs.sort((a, b) => {
536566
const da = distances[a.blockId]
537567
const db = distances[b.blockId]
@@ -591,7 +621,7 @@ export function ColumnSidebar({
591621
fullOutputs.push({ blockId: o.blockId, path: o.path, columnName: colName })
592622
newOutputColumns.push({
593623
name: colName,
594-
type: 'string',
624+
type: columnTypeForLeaf(o.leafType),
595625
required: false,
596626
unique: false,
597627
workflowGroupId: existingGroup.id,
@@ -620,7 +650,7 @@ export function ColumnSidebar({
620650
taken.add(colName)
621651
newOutputColumns.push({
622652
name: colName,
623-
type: 'string',
653+
type: columnTypeForLeaf(o.leafType),
624654
required: false,
625655
unique: false,
626656
workflowGroupId: groupId,

0 commit comments

Comments
 (0)