@@ -309,6 +309,14 @@ interface TableGridProps {
309309 draftSelectSaveSinkRef : React . MutableRefObject <
310310 ( ( options : SelectOption [ ] , multiple : boolean ) => Promise < boolean > ) | null
311311 >
312+ /**
313+ * Ref the grid populates with the sidebar's successful type-conversion undo
314+ * recorder, keeping the undo stack owned by the grid.
315+ */
316+ recordColumnTypeChangeSinkRef : React . MutableRefObject <
317+ | ( ( columnName : string , previousColumn : ColumnDefinition , newColumn : ColumnDefinition ) => void )
318+ | null
319+ >
312320 /**
313321 * Ref the grid populates with its draft discard. The wrapper fires it from
314322 * every slideout transition other than entering `draft-select`, so
@@ -501,6 +509,7 @@ export function TableGrid({
501509 columnRenameSinkRef,
502510 addColumnOfTypeSinkRef,
503511 draftSelectSaveSinkRef,
512+ recordColumnTypeChangeSinkRef,
504513 abortColumnDraftSinkRef,
505514 layoutSnapshotSinkRef,
506515 afterDeleteRowsSinkRef,
@@ -1540,7 +1549,6 @@ export function TableGrid({
15401549 const handleFindCloseRef = useRef ( handleFindClose )
15411550 handleFindCloseRef . current = handleFindClose
15421551
1543- /** True after a refused rename — paints the header input red until it's edited. */
15441552 const [ renameError , setRenameError ] = useState ( false )
15451553
15461554 const columnRename = useInlineRename ( {
@@ -3946,9 +3954,13 @@ export function TableGrid({
39463954 { name, type : 'string' , position : index } ,
39473955 {
39483956 onSuccess : ( result ) => {
3949- const newId = result . data . columns . find ( ( c ) => c . name === name ) ?. id ?? name
3957+ const createdColumn = result . data . columns . find ( ( c ) => c . name === name ) ?? {
3958+ name,
3959+ type : 'string' as const ,
3960+ }
3961+ const newId = getColumnId ( createdColumn )
39503962 pushUndoRef . current (
3951- { type : 'create-column' , columnName : name , columnId : newId , position : index } ,
3963+ { type : 'create-column' , column : createdColumn , position : index } ,
39523964 owner
39533965 )
39543966 // Skipped after a mid-flight view switch: the destination re-seeded
@@ -3973,11 +3985,12 @@ export function TableGrid({
39733985 { name, type : 'string' , position } ,
39743986 {
39753987 onSuccess : ( result ) => {
3976- const newId = result . data . columns . find ( ( c ) => c . name === name ) ?. id ?? name
3977- pushUndoRef . current (
3978- { type : 'create-column' , columnName : name , columnId : newId , position } ,
3979- owner
3980- )
3988+ const createdColumn = result . data . columns . find ( ( c ) => c . name === name ) ?? {
3989+ name,
3990+ type : 'string' as const ,
3991+ }
3992+ const newId = getColumnId ( createdColumn )
3993+ pushUndoRef . current ( { type : 'create-column' , column : createdColumn , position } , owner )
39813994 if ( owner === viewLayoutKeyRef . current ) insertColumnInOrder ( columnId , newId , 'right' )
39823995 } ,
39833996 }
@@ -4042,11 +4055,12 @@ export function TableGrid({
40424055 draftPersistingRef . current = true
40434056 try {
40444057 const result = await addColumnMutation . mutateAsync ( { name, type : draft . type , ...metadata } )
4045- const newId = result . data . columns . find ( ( c ) => c . name === name ) ?. id ?? name
4046- pushUndoRef . current (
4047- { type : 'create-column' , columnName : name , columnId : newId , position } ,
4048- owner
4049- )
4058+ const createdColumn = result . data . columns . find ( ( c ) => c . name === name ) ?? {
4059+ name,
4060+ type : draft . type ,
4061+ ...metadata ,
4062+ }
4063+ pushUndoRef . current ( { type : 'create-column' , column : createdColumn , position } , owner )
40504064 setColumnDraft ( null )
40514065 return true
40524066 } catch ( err ) {
@@ -4089,19 +4103,25 @@ export function TableGrid({
40894103 persistDraft ( { options, ...( multiple ? { multiple : true } : { } ) } )
40904104 abortColumnDraftSinkRef . current = ( ) => setColumnDraft ( null )
40914105
4092- /** Toggle the `unique` constraint on a plain column, recording the flip for undo. */
4106+ /** Toggle the `unique` constraint on a plain column, recording successful flips for undo. */
40934107 const handleToggleUnique = useCallback ( ( columnKey : string ) => {
40944108 const column = columnsRef . current . find ( ( c ) => c . key === columnKey )
40954109 if ( ! column ) return
40964110 const previousValue = ! ! column . unique
4097- pushUndoRef . current ( {
4098- type : 'toggle-column-constraint' ,
4099- columnName : columnKey ,
4100- constraint : 'unique' ,
4101- previousValue,
4102- newValue : ! previousValue ,
4103- } )
4104- updateColumnMutation . mutate ( { columnName : columnKey , updates : { unique : ! previousValue } } )
4111+ updateColumnMutation . mutate (
4112+ { columnName : columnKey , updates : { unique : ! previousValue } } ,
4113+ {
4114+ onSuccess : ( ) => {
4115+ pushUndoRef . current ( {
4116+ type : 'toggle-column-constraint' ,
4117+ columnName : columnKey ,
4118+ constraint : 'unique' ,
4119+ previousValue,
4120+ newValue : ! previousValue ,
4121+ } )
4122+ } ,
4123+ }
4124+ )
41054125 } , [ ] )
41064126
41074127 /** Open the workflow-config sidebar to spawn a brand-new workflow group. */
@@ -4128,7 +4148,6 @@ export function TableGrid({
41284148 [ onOpenWorkflowConfig , workflowGroupById ]
41294149 )
41304150
4131- /** Starts the inline header rename from the menu's "Rename column" item. */
41324151 const handleRenameColumn = useCallback (
41334152 ( columnName : string ) => {
41344153 const column = columnsRef . current . find ( ( c ) => c . key === columnName )
@@ -4150,22 +4169,41 @@ export function TableGrid({
41504169 onOpenColumnConfig ( { mode : 'convert-select' , columnName } )
41514170 return
41524171 }
4153- const previousType = column . type
41544172 // Recorded on success only: the server refuses a retype whose existing
41554173 // values can't convert (the hook toasts why), and an entry for a change
41564174 // that never landed would make undo "restore" the type it already has.
41574175 updateColumnMutation . mutate (
41584176 { columnName, updates : { type : newType } } ,
41594177 {
4160- onSuccess : ( ) => {
4161- pushUndoRef . current ( { type : 'update-column-type' , columnName, previousType, newType } )
4178+ onSuccess : ( result ) => {
4179+ const updatedColumn = result . data . columns . find (
4180+ ( candidate ) => getColumnId ( candidate ) === columnName
4181+ ) ?? {
4182+ ...column ,
4183+ type : newType ,
4184+ }
4185+ pushUndoRef . current ( {
4186+ type : 'update-column-type' ,
4187+ columnName,
4188+ previousColumn : column ,
4189+ newColumn : updatedColumn ,
4190+ } )
41624191 } ,
41634192 }
41644193 )
41654194 } ,
41664195 [ onOpenColumnConfig ]
41674196 )
41684197
4198+ recordColumnTypeChangeSinkRef . current = ( columnName , previousColumn , newColumn ) => {
4199+ pushUndoRef . current ( {
4200+ type : 'update-column-type' ,
4201+ columnName,
4202+ previousColumn,
4203+ newColumn,
4204+ } )
4205+ }
4206+
41694207 /** Opens the config sidebar for a select's options / a currency's code. */
41704208 const handleOpenConfigure = useCallback (
41714209 ( columnName : string ) => {
@@ -4192,12 +4230,6 @@ export function TableGrid({
41924230 deleteWorkflowGroupRef . current ( { groupId } )
41934231 } , [ ] )
41944232
4195- /**
4196- * Computes the names slated for deletion given a click on `columnName` and
4197- * the current column selection. If the click landed inside a multi-column
4198- * selection, the entire selection is the target; otherwise it's just the
4199- * clicked column.
4200- */
42014233 const resolveDeletionNames = useCallback ( ( columnName : string ) : string [ ] => {
42024234 const cols = columnsRef . current
42034235 if ( isColumnSelectionRef . current && selectionAnchorRef . current ) {
0 commit comments