Skip to content

Commit fa28ff3

Browse files
Change new column behavior
1 parent 38a3818 commit fa28ff3

7 files changed

Lines changed: 178 additions & 233 deletions

File tree

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

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,18 @@ import {
3333
} from '@/hooks/queries/tables'
3434
import { useWorkflowState, workflowKeys } from '@/hooks/queries/workflows'
3535
import type { WorkflowMetadata } from '@/stores/workflows/registry/types'
36-
import { COLUMN_TYPE_OPTIONS } from './column-types'
36+
import { COLUMN_TYPE_OPTIONS, type SidebarColumnType } from './column-types'
3737

3838
export type ColumnConfigState =
3939
| { mode: 'edit'; columnName: string }
4040
| { mode: 'new'; columnName: string; workflowId: string; proposedName: string }
41-
| { mode: 'create'; columnName: string; workflowId: string; proposedName: string }
41+
| {
42+
mode: 'create'
43+
columnName: string
44+
proposedName: string
45+
/** When present, the sidebar opens with the workflow type pre-selected. */
46+
workflowId?: string
47+
}
4248
| null
4349

4450
interface ColumnSidebarProps {
@@ -262,10 +268,11 @@ export function ColumnSidebar({
262268
return workflowGroups.find((g) => g.id === existingColumn.workflowGroupId)
263269
}, [existingColumn, workflowGroups])
264270

271+
const [nameInput, setNameInput] = useState<string>('')
272+
const [typeInput, setTypeInput] = useState<SidebarColumnType>('string')
273+
265274
const isWorkflow =
266-
!!existingGroup ||
267-
configState?.mode === 'new' ||
268-
(configState?.mode === 'create' && 'workflowId' in configState && !!configState.workflowId)
275+
!!existingGroup || configState?.mode === 'new' || typeInput === 'workflow'
269276

270277
/**
271278
* Columns to the left of the current column — these are the only valid trigger
@@ -281,8 +288,6 @@ export function ColumnSidebar({
281288
return allColumns.slice(0, idx)
282289
}, [configState, allColumns])
283290

284-
const [nameInput, setNameInput] = useState<string>('')
285-
const [typeInput, setTypeInput] = useState<ColumnDefinition['type']>('string')
286291
const [uniqueInput, setUniqueInput] = useState<boolean>(false)
287292
const [selectedWorkflowId, setSelectedWorkflowId] = useState<string>('')
288293
const [deps, setDeps] = useState<string[]>([])
@@ -308,13 +313,14 @@ export function ColumnSidebar({
308313
return cols.slice(0, idx)
309314
})()
310315
if (configState.mode === 'edit') {
311-
const type = existing?.type ?? 'string'
312-
setTypeInput(type)
313-
setUniqueInput(!!existing?.unique)
314-
setNameInput(existing?.name ?? configState.columnName)
315316
const group = existing?.workflowGroupId
316317
? workflowGroups.find((g) => g.id === existing.workflowGroupId)
317318
: undefined
319+
// Surface workflow-typed columns as `'workflow'` in the combobox even
320+
// though they're stored as scalar columns under the hood.
321+
setTypeInput(group ? 'workflow' : (existing?.type ?? 'string'))
322+
setUniqueInput(!!existing?.unique)
323+
setNameInput(existing?.name ?? configState.columnName)
318324
if (group) {
319325
setSelectedWorkflowId(group.workflowId)
320326
setDeps(group.dependencies?.columns ?? leftOfCurrent.map((c) => c.name))
@@ -325,10 +331,12 @@ export function ColumnSidebar({
325331
setSelectedOutputs([])
326332
}
327333
} else {
328-
setTypeInput('string')
334+
const workflowId =
335+
'workflowId' in configState && configState.workflowId ? configState.workflowId : ''
336+
setTypeInput(workflowId ? 'workflow' : 'string')
329337
setUniqueInput(false)
330338
setNameInput(configState.proposedName)
331-
setSelectedWorkflowId(configState.workflowId)
339+
setSelectedWorkflowId(workflowId)
332340
setDeps(leftOfCurrent.map((c) => c.name))
333341
setSelectedOutputs([])
334342
}
@@ -670,15 +678,18 @@ export function ColumnSidebar({
670678
toast.success(`Added "${workflowName}"`)
671679
}
672680
} else if (configState.mode === 'create') {
681+
// `isWorkflow` is false here, so `typeInput` is a real ColumnDefinition type.
682+
const scalarType = typeInput as ColumnDefinition['type']
673683
await addColumn.mutateAsync({
674684
name: trimmedName,
675-
type: typeInput,
685+
type: scalarType,
676686
})
677687
toast.success(`Added "${trimmedName}"`)
678688
} else {
679689
const existing = existingColumnRef.current
690+
const scalarType = typeInput as ColumnDefinition['type']
680691
const renamed = trimmedName !== configState.columnName
681-
const typeChanged = !!existing && existing.type !== typeInput
692+
const typeChanged = !!existing && existing.type !== scalarType
682693
const uniqueChanged = !!existing && !!existing.unique !== uniqueInput
683694

684695
const updates: {
@@ -687,7 +698,7 @@ export function ColumnSidebar({
687698
unique?: boolean
688699
} = {
689700
...(renamed ? { name: trimmedName } : {}),
690-
...(typeChanged ? { type: typeInput } : {}),
701+
...(typeChanged ? { type: scalarType } : {}),
691702
...(uniqueChanged ? { unique: uniqueInput } : {}),
692703
}
693704

@@ -709,11 +720,7 @@ export function ColumnSidebar({
709720
}
710721
}
711722

712-
const saveDisabled =
713-
updateColumn.isPending ||
714-
addColumn.isPending ||
715-
!nameInput.trim() ||
716-
(isWorkflow && (!selectedWorkflowId || selectedOutputs.length === 0))
723+
const saveDisabled = updateColumn.isPending || addColumn.isPending
717724

718725
return (
719726
<aside
@@ -739,6 +746,20 @@ export function ColumnSidebar({
739746
</div>
740747

741748
<div className='flex-1 overflow-y-auto overflow-x-hidden px-2 pt-3 pb-2 [overflow-anchor:none]'>
749+
<div className='flex flex-col gap-[9.5px]'>
750+
<FieldLabel required>Type</FieldLabel>
751+
<Combobox
752+
options={typeOptions}
753+
value={typeInput}
754+
onChange={(v) => setTypeInput(v as SidebarColumnType)}
755+
placeholder='Select type'
756+
searchable
757+
searchPlaceholder='Search types...'
758+
/>
759+
</div>
760+
761+
<FieldDivider />
762+
742763
<div className='flex flex-col gap-[9.5px]'>
743764
<FieldLabel htmlFor='column-sidebar-name' required>
744765
Column name
@@ -756,18 +777,6 @@ export function ColumnSidebar({
756777
)}
757778
</div>
758779

759-
<FieldDivider />
760-
761-
<div className='flex flex-col gap-[9.5px]'>
762-
<FieldLabel required>Type</FieldLabel>
763-
<Combobox
764-
options={typeOptions}
765-
value={typeInput}
766-
onChange={(v) => setTypeInput(v as ColumnDefinition['type'])}
767-
placeholder='Select type'
768-
/>
769-
</div>
770-
771780
{!isWorkflow && (
772781
<>
773782
<FieldDivider />
@@ -859,6 +868,8 @@ export function ColumnSidebar({
859868
disabled={!workflows || workflows.length === 0}
860869
emptyMessage='No manual triggers configured'
861870
maxHeight={260}
871+
searchable
872+
searchPlaceholder='Search workflows...'
862873
error={showValidation && !selectedWorkflowId ? 'Select a workflow' : null}
863874
/>
864875
{showValidation && !selectedWorkflowId && (

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
import type React from 'react'
22
import {
33
Calendar as CalendarIcon,
4+
PlayOutline,
45
TypeBoolean,
56
TypeJson,
67
TypeNumber,
78
TypeText,
89
} from '@/components/emcn/icons'
910
import type { ColumnDefinition } from '@/lib/table'
1011

12+
/**
13+
* UI-only column type. `'workflow'` is a virtual selection that lets the user
14+
* configure a workflow group from the sidebar; on save, it expands into N real
15+
* scalar columns + one workflow group, none of which carry a `'workflow'` type.
16+
*/
17+
export type SidebarColumnType = ColumnDefinition['type'] | 'workflow'
18+
1119
export interface ColumnTypeOption {
12-
type: ColumnDefinition['type']
20+
type: SidebarColumnType
1321
label: string
1422
icon: React.ComponentType<{ className?: string }>
1523
}
@@ -20,4 +28,5 @@ export const COLUMN_TYPE_OPTIONS: ColumnTypeOption[] = [
2028
{ type: 'boolean', label: 'Boolean', icon: TypeBoolean },
2129
{ type: 'date', label: 'Date', icon: CalendarIcon },
2230
{ type: 'json', label: 'JSON', icon: TypeJson },
31+
{ type: 'workflow', label: 'Workflow', icon: PlayOutline },
2332
]

0 commit comments

Comments
 (0)