@@ -20,16 +20,20 @@ import {
2020 ArrowUp ,
2121 Eye ,
2222 EyeOff ,
23+ Fingerprint ,
2324 Pencil ,
2425 Pin ,
2526 PinOff ,
2627 PlayOutline ,
28+ Settings ,
2729 Trash ,
2830 Workflow ,
2931 X ,
3032} from '@sim/emcn/icons'
3133import type { RunLimit , RunMode } from '@/lib/api/contracts/tables'
32- import type { SortDirection , WorkflowGroupType } from '@/lib/table'
34+ import type { ColumnDefinition , SortDirection , WorkflowGroupType } from '@/lib/table'
35+ import { columnTypeOf } from '@/lib/table/column-types'
36+ import { PLAIN_COLUMN_TYPE_OPTIONS } from '@/app/workspace/[workspaceId]/tables/[tableId]/components/column-config-sidebar'
3337import { HeaderLabel } from '@/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/headers/header-label'
3438import { getEnrichment } from '@/enrichments/registry'
3539import type { WorkflowMetadata } from '@/stores/workflows/registry/types'
@@ -69,9 +73,24 @@ interface ColumnOptionsMenuProps {
6973 * destructive action is non-lossy (workflow-output column where removing
7074 * it leaves the group with siblings). */
7175 deleteLabel ?: string
72- onOpenConfig : ( columnName : string ) => void
76+ /** Renders the "Edit column" item. Only workflow-owned columns still have a
77+ * config surface behind it (the workflow sidebar); plain columns edit
78+ * name/type/unique from this menu directly and omit it. */
79+ onOpenConfig ?: ( columnName : string ) => void
80+ /** Starts the inline header rename. Plain and enrichment columns only. */
81+ onRenameColumn ?: ( columnName : string ) => void
82+ /** Converts the column to `type`. Callers route `select` conversions through
83+ * the config sidebar (the option set must be collected first). */
84+ onChangeType ?: ( columnName : string , type : ColumnDefinition [ 'type' ] ) => void
85+ /** Opens the config sidebar for a type with per-column configuration
86+ * (registry `hasConfiguration`) — a select's options, a currency's code. */
87+ onConfigure ?: ( columnName : string ) => void
7388 onInsertLeft : ( columnName : string ) => void
7489 onInsertRight : ( columnName : string ) => void
90+ /** Flip the column's `unique` constraint. Callers pass it only for columns
91+ * that can carry one (plain/enrichment columns of a `supportsUnique` type),
92+ * so the item's presence is the capability check. */
93+ onToggleUnique ?: ( columnName : string ) => void
7594 onDeleteColumn : ( columnName : string ) => void
7695 /** When provided (i.e. menu opened from a workflow-group meta header), the
7796 * "Delete" item deletes the entire workflow group rather than the single
@@ -112,8 +131,9 @@ interface ColumnOptionsMenuProps {
112131 * Shared column-options dropdown rendered next to the column header chevron
113132 * AND on right-click of the workflow group meta cell. Anchors to a fixed
114133 * position passed in (so callers can place it under the chevron, or at the
115- * cursor for context-menu use). Rename / change type / unique live in the
116- * column sidebar (opened by Edit column).
134+ * cursor for context-menu use). Rename, change type, and the unique
135+ * constraint are handled from here; per-type configuration and workflow
136+ * outputs open their sidebars.
117137 */
118138export function ColumnOptionsMenu ( {
119139 open,
@@ -122,8 +142,12 @@ export function ColumnOptionsMenu({
122142 column,
123143 deleteLabel,
124144 onOpenConfig,
145+ onRenameColumn,
146+ onChangeType,
147+ onConfigure,
125148 onInsertLeft,
126149 onInsertRight,
150+ onToggleUnique,
127151 onDeleteColumn,
128152 onDeleteGroup,
129153 onRunColumnAll,
@@ -142,6 +166,8 @@ export function ColumnOptionsMenu({
142166 const showRunActions = Boolean ( onRunColumnAll && onRunColumnIncomplete )
143167 const showRunSelected = Boolean ( onRunColumnSelected ) && selectedRowCount > 0
144168 const runLabels = runMenuLabels ( hasActiveFilter )
169+ const typeDefinition = columnTypeOf ( column )
170+ const CurrentTypeIcon = typeDefinition . icon
145171 return (
146172 < DropdownMenu open = { open } onOpenChange = { onOpenChange } >
147173 < DropdownMenuTrigger asChild >
@@ -228,10 +254,53 @@ export function ColumnOptionsMenu({
228254 View workflow
229255 </ DropdownMenuItem >
230256 ) }
231- < DropdownMenuItem onSelect = { ( ) => onOpenConfig ( column . key ) } >
232- < Pencil />
233- Edit column
234- </ DropdownMenuItem >
257+ { onOpenConfig && (
258+ < DropdownMenuItem onSelect = { ( ) => onOpenConfig ( column . key ) } >
259+ < Pencil />
260+ Edit column
261+ </ DropdownMenuItem >
262+ ) }
263+ { onRenameColumn && (
264+ < DropdownMenuItem onSelect = { ( ) => onRenameColumn ( column . key ) } >
265+ < Pencil />
266+ Rename column
267+ </ DropdownMenuItem >
268+ ) }
269+ { onChangeType && (
270+ < DropdownMenuSub >
271+ < DropdownMenuSubTrigger >
272+ < CurrentTypeIcon />
273+ Change type
274+ </ DropdownMenuSubTrigger >
275+ < DropdownMenuSubContent >
276+ { PLAIN_COLUMN_TYPE_OPTIONS . map ( ( option ) => {
277+ const Icon = option . icon
278+ return (
279+ < DropdownMenuItem
280+ key = { option . type }
281+ active = { column . type === option . type }
282+ onSelect = { ( ) => onChangeType ( column . key , option . type ) }
283+ >
284+ < Icon />
285+ { option . label }
286+ </ DropdownMenuItem >
287+ )
288+ } ) }
289+ </ DropdownMenuSubContent >
290+ </ DropdownMenuSub >
291+ ) }
292+ { onConfigure && typeDefinition . hasConfiguration && (
293+ < DropdownMenuItem onSelect = { ( ) => onConfigure ( column . key ) } >
294+ < Settings />
295+ { `Configure ${ typeDefinition . label . toLowerCase ( ) } ` }
296+ </ DropdownMenuItem >
297+ ) }
298+ { onToggleUnique && (
299+ < DropdownMenuItem onSelect = { ( ) => onToggleUnique ( column . key ) } >
300+ < Fingerprint />
301+ { column . unique ? 'Remove unique' : 'Set unique' }
302+ </ DropdownMenuItem >
303+ ) }
235304 { onPinToggle && (
236305 < DropdownMenuItem onSelect = { ( ) => onPinToggle ( column . key ) } >
237306 { isPinned ? < PinOff /> : < Pin /> }
0 commit comments