@@ -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'
@@ -91,6 +92,7 @@ import {
9192 chipRowCount ,
9293 classifyExecStatusMix ,
9394 collectRowSnapshots ,
95+ columnNameIssue ,
9496 computeNormalizedSelection ,
9597 drainTargetForChip ,
9698 type ExecStatusMix ,
@@ -1568,16 +1570,60 @@ export function TableGrid({
15681570 const handleFindCloseRef = useRef ( handleFindClose )
15691571 handleFindCloseRef . current = handleFindClose
15701572
1573+ const [ renameError , setRenameError ] = useState ( false )
1574+
15711575 const columnRename = useInlineRename ( {
15721576 // `columnName` is the column id; record the prior display name + id so undo
15731577 // restores the label (not the id) and targets the right column.
15741578 onSave : ( columnName , newName ) => {
15751579 const oldName = columnsRef . current . find ( ( c ) => c . key === columnName ) ?. name ?? columnName
15761580 pushUndoRef . current ( { type : 'rename-column' , oldName, newName, columnId : columnName } )
15771581 handleColumnRename ( columnName , newName )
1578- return updateColumnMutation . mutateAsync ( { columnName, updates : { name : newName } } )
1582+ return updateColumnMutation
1583+ . mutateAsync ( { columnName, updates : { name : newName } } )
1584+ . catch ( ( error : unknown ) => {
1585+ if ( isValidationError ( error ) ) {
1586+ toast . error ( extractValidationIssues ( error ) [ 0 ] ?. message ?? getErrorMessage ( error ) )
1587+ }
1588+ setRenameError ( true )
1589+ throw error
1590+ } )
15791591 } ,
15801592 } )
1593+ const columnRenameRef = useRef ( columnRename )
1594+ columnRenameRef . current = columnRename
1595+
1596+ const handleRenameValueChange = useCallback ( ( value : string ) => {
1597+ setRenameError ( false )
1598+ columnRenameRef . current . setEditValue ( value )
1599+ } , [ ] )
1600+
1601+ /** Keeps invalid names in the header so the user can correct them in place. */
1602+ const handleRenameSubmit = useCallback ( ( ) => {
1603+ const { editingId, editValue, submitRename } = columnRenameRef . current
1604+ const trimmedName = editValue . trim ( )
1605+ const currentColumn = columnsRef . current . find ( ( column ) => column . key === editingId )
1606+ if ( trimmedName && currentColumn && trimmedName !== currentColumn . name ) {
1607+ const issue = columnNameIssue (
1608+ trimmedName ,
1609+ schemaColumnsRef . current
1610+ . filter ( ( column ) => getColumnId ( column ) !== editingId )
1611+ . map ( ( column ) => column . name )
1612+ )
1613+ if ( issue ) {
1614+ toast . error ( issue )
1615+ setRenameError ( true )
1616+ return
1617+ }
1618+ }
1619+ setRenameError ( false )
1620+ void submitRename ( )
1621+ } , [ ] )
1622+
1623+ const handleRenameCancel = useCallback ( ( ) => {
1624+ setRenameError ( false )
1625+ columnRenameRef . current . cancelRename ( )
1626+ } , [ ] )
15811627
15821628 const toggleBooleanCell = useCallback (
15831629 ( rowId : string , columnName : string , currentValue : unknown ) => {
@@ -4071,6 +4117,15 @@ export function TableGrid({
40714117 [ onOpenColumnConfig , onOpenWorkflowConfig , workflowGroupById ]
40724118 )
40734119
4120+ const handleRenameColumn = useCallback (
4121+ ( columnName : string ) => {
4122+ setRenameError ( false )
4123+ const column = columnsRef . current . find ( ( candidate ) => candidate . key === columnName )
4124+ columnRename . startRename ( columnName , column ?. name ?? columnName )
4125+ } ,
4126+ [ columnRename . startRename ]
4127+ )
4128+
40744129 const handleConfigureWorkflowGroup = useCallback (
40754130 ( groupId : string ) => {
40764131 const group = workflowGroupById . get ( groupId )
@@ -4961,9 +5016,10 @@ export function TableGrid({
49615016 renameValue = {
49625017 columnRename . editingId === column . key ? columnRename . editValue : ''
49635018 }
4964- onRenameValueChange = { columnRename . setEditValue }
4965- onRenameSubmit = { columnRename . submitRename }
4966- onRenameCancel = { columnRename . cancelRename }
5019+ renameError = { renameError && columnRename . editingId === column . key }
5020+ onRenameValueChange = { handleRenameValueChange }
5021+ onRenameSubmit = { handleRenameSubmit }
5022+ onRenameCancel = { handleRenameCancel }
49675023 onColumnSelect = { handleColumnSelect }
49685024 // Required props here, and the menu is already
49695025 // suppressed for non-editors by `readOnly`.
@@ -4988,6 +5044,9 @@ export function TableGrid({
49885044 workflowGroups = { tableWorkflowGroups }
49895045 sourceInfo = { columnSourceInfo . get ( column . key ) }
49905046 onOpenConfig = { handleConfigureColumn }
5047+ onRenameColumn = {
5048+ userPermissions . canEdit ? handleRenameColumn : undefined
5049+ }
49915050 onGoToReferenceTable = {
49925051 referenceColumnsEnabled ? handleGoToReferenceTable : undefined
49935052 }
0 commit comments