@@ -11,6 +11,7 @@ import { assessTextPaste, formatPasteLimit, PASTE_LIMITS } from '@sim/utils/past
1111import { useVirtualizer } from '@tanstack/react-virtual'
1212import { useParams , useRouter } from 'next/navigation'
1313import { usePostHog } from 'posthog-js/react'
14+ import { extractValidationIssues , isValidationError } from '@/lib/api/client/errors'
1415import type { RunLimit , RunMode , TableFindMatch } from '@/lib/api/contracts/tables'
1516import { attachSelectionContextToClipboard } from '@/lib/copilot/chat/selection-clipboard'
1617import { captureEvent } from '@/lib/posthog/client'
@@ -93,6 +94,7 @@ import {
9394 chipRowCount ,
9495 classifyExecStatusMix ,
9596 collectRowSnapshots ,
97+ columnNameIssue ,
9698 computeNormalizedSelection ,
9799 drainTargetForChip ,
98100 type ExecStatusMix ,
@@ -1583,16 +1585,60 @@ export function TableGrid({
15831585 const handleFindCloseRef = useRef ( handleFindClose )
15841586 handleFindCloseRef . current = handleFindClose
15851587
1588+ const [ renameError , setRenameError ] = useState ( false )
1589+
15861590 const columnRename = useInlineRename ( {
15871591 // `columnName` is the column id; record the prior display name + id so undo
15881592 // restores the label (not the id) and targets the right column.
15891593 onSave : ( columnName , newName ) => {
15901594 const oldName = columnsRef . current . find ( ( c ) => c . key === columnName ) ?. name ?? columnName
15911595 pushUndoRef . current ( { type : 'rename-column' , oldName, newName, columnId : columnName } )
15921596 handleColumnRename ( columnName , newName )
1593- return updateColumnMutation . mutateAsync ( { columnName, updates : { name : newName } } )
1597+ return updateColumnMutation
1598+ . mutateAsync ( { columnName, updates : { name : newName } } )
1599+ . catch ( ( error : unknown ) => {
1600+ if ( isValidationError ( error ) ) {
1601+ toast . error ( extractValidationIssues ( error ) [ 0 ] ?. message ?? getErrorMessage ( error ) )
1602+ }
1603+ setRenameError ( true )
1604+ throw error
1605+ } )
15941606 } ,
15951607 } )
1608+ const columnRenameRef = useRef ( columnRename )
1609+ columnRenameRef . current = columnRename
1610+
1611+ const handleRenameValueChange = useCallback ( ( value : string ) => {
1612+ setRenameError ( false )
1613+ columnRenameRef . current . setEditValue ( value )
1614+ } , [ ] )
1615+
1616+ /** Keeps invalid names in the header so the user can correct them in place. */
1617+ const handleRenameSubmit = useCallback ( ( ) => {
1618+ const { editingId, editValue, submitRename } = columnRenameRef . current
1619+ const trimmedName = editValue . trim ( )
1620+ const currentColumn = columnsRef . current . find ( ( column ) => column . key === editingId )
1621+ if ( trimmedName && currentColumn && trimmedName !== currentColumn . name ) {
1622+ const issue = columnNameIssue (
1623+ trimmedName ,
1624+ schemaColumnsRef . current
1625+ . filter ( ( column ) => getColumnId ( column ) !== editingId )
1626+ . map ( ( column ) => column . name )
1627+ )
1628+ if ( issue ) {
1629+ toast . error ( issue )
1630+ setRenameError ( true )
1631+ return
1632+ }
1633+ }
1634+ setRenameError ( false )
1635+ void submitRename ( )
1636+ } , [ ] )
1637+
1638+ const handleRenameCancel = useCallback ( ( ) => {
1639+ setRenameError ( false )
1640+ columnRenameRef . current . cancelRename ( )
1641+ } , [ ] )
15961642
15971643 const toggleBooleanCell = useCallback (
15981644 ( rowId : string , columnName : string , currentValue : unknown ) => {
@@ -4125,6 +4171,15 @@ export function TableGrid({
41254171 [ onOpenColumnConfig , onOpenWorkflowConfig , workflowGroupById ]
41264172 )
41274173
4174+ const handleRenameColumn = useCallback (
4175+ ( columnName : string ) => {
4176+ setRenameError ( false )
4177+ const column = columnsRef . current . find ( ( candidate ) => candidate . key === columnName )
4178+ columnRename . startRename ( columnName , column ?. name ?? columnName )
4179+ } ,
4180+ [ columnRename . startRename ]
4181+ )
4182+
41284183 const handleConfigureWorkflowGroup = useCallback (
41294184 ( groupId : string ) => {
41304185 const group = workflowGroupById . get ( groupId )
@@ -5021,9 +5076,10 @@ export function TableGrid({
50215076 renameValue = {
50225077 columnRename . editingId === column . key ? columnRename . editValue : ''
50235078 }
5024- onRenameValueChange = { columnRename . setEditValue }
5025- onRenameSubmit = { columnRename . submitRename }
5026- onRenameCancel = { columnRename . cancelRename }
5079+ renameError = { renameError && columnRename . editingId === column . key }
5080+ onRenameValueChange = { handleRenameValueChange }
5081+ onRenameSubmit = { handleRenameSubmit }
5082+ onRenameCancel = { handleRenameCancel }
50275083 onColumnSelect = { handleColumnSelect }
50285084 // Required props here, and the menu is already
50295085 // suppressed for non-editors by `readOnly`.
@@ -5054,6 +5110,9 @@ export function TableGrid({
50545110 deleteLockedReason = {
50555111 locks ?. deleteLocked ? LOCK_TOOLTIPS . delete : undefined
50565112 }
5113+ onRenameColumn = {
5114+ userPermissions . canEdit ? handleRenameColumn : undefined
5115+ }
50575116 onGoToReferenceTable = {
50585117 referenceColumnsEnabled ? handleGoToReferenceTable : undefined
50595118 }
0 commit comments