Skip to content

Commit 7518b00

Browse files
committed
fix(tables): keep column rename migration atomic
1 parent 3ceae0c commit 7518b00

3 files changed

Lines changed: 28 additions & 47 deletions

File tree

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

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,6 @@ function findButton(label: string): HTMLButtonElement | undefined {
100100
)
101101
}
102102

103-
function setInputValue(input: HTMLInputElement, value: string): void {
104-
const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set
105-
valueSetter?.call(input, value)
106-
input.dispatchEvent(new Event('input', { bubbles: true }))
107-
}
108-
109103
beforeEach(() => {
110104
globalThis.IS_REACT_ACT_ENVIRONMENT = true
111105
container = document.createElement('div')
@@ -186,8 +180,7 @@ describe('ColumnConfigSidebar', () => {
186180
expect(mockUpdateColumn).not.toHaveBeenCalled()
187181
})
188182

189-
it('edits a Reference column name and target table together', async () => {
190-
const onColumnRename = vi.fn()
183+
it('edits Reference configuration without exposing column renaming', async () => {
191184
await act(async () => {
192185
root.render(
193186
<ColumnConfigSidebar
@@ -201,26 +194,20 @@ describe('ColumnConfigSidebar', () => {
201194
}}
202195
workspaceId='workspace-1'
203196
tableId='table-current'
204-
onColumnRename={onColumnRename}
205197
/>
206198
)
207199
})
208200

209-
const nameInput = container.querySelector<HTMLInputElement>('#column-sidebar-name')
210-
expect(nameInput?.value).toBe('Related row')
201+
expect(container).not.toHaveTextContent('Column name')
202+
expect(container.querySelector('#column-sidebar-name')).toBeNull()
211203

212-
act(() => setInputValue(nameInput!, 'Renamed relation'))
213204
act(() => findCombobox('Select table')?.onChange?.('table-customers'))
214205
await act(async () => findButton('Save')?.click())
215206

216207
expect(mockUpdateColumn).toHaveBeenCalledWith({
217208
columnName: 'col-reference',
218-
updates: {
219-
name: 'Renamed relation',
220-
referenceTableId: 'table-customers',
221-
},
209+
updates: { referenceTableId: 'table-customers' },
222210
})
223-
expect(onColumnRename).toHaveBeenCalledWith('col-reference', 'Renamed relation')
224211
})
225212

226213
it('keeps Select options in the edit sidebar', async () => {

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

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ interface ColumnConfigSidebarProps {
5757
tableRowTtlEnabled: boolean
5858
workspaceId: string
5959
tableId: string
60-
/** Notify the grid so local layout metadata follows a successful rename. */
61-
onColumnRename?: (oldName: string, newName: string) => void
6260
}
6361

6462
/**
@@ -108,7 +106,6 @@ function ColumnConfigBody({
108106
tableRowTtlEnabled,
109107
workspaceId,
110108
tableId,
111-
onColumnRename,
112109
}: ColumnConfigBodyProps) {
113110
const updateColumn = useUpdateColumn({ workspaceId, tableId })
114111
const addColumn = useAddTableColumn({ workspaceId, tableId })
@@ -169,7 +166,7 @@ function ColumnConfigBody({
169166
}
170167

171168
async function handleSave() {
172-
if (!trimmedName) {
169+
if (config.mode === 'create' && !trimmedName) {
173170
setShowValidation(true)
174171
return
175172
}
@@ -201,7 +198,6 @@ function ColumnConfigBody({
201198
return
202199
}
203200

204-
const renamed = trimmedName !== (existingColumn?.name ?? config.columnName)
205201
const typeChanged = !!existingColumn && existingColumn.type !== typeInput
206202
const uniqueChanged =
207203
supportsUnique && !!existingColumn && !!existingColumn.unique !== uniqueInput
@@ -215,15 +211,13 @@ function ColumnConfigBody({
215211
wantsReference && existingColumn?.referenceTableId !== referenceTableInput
216212

217213
const updates: {
218-
name?: string
219214
type?: ColumnDefinition['type']
220215
unique?: boolean
221216
options?: SelectOption[]
222217
multiple?: boolean
223218
currencyCode?: string
224219
referenceTableId?: string
225220
} = {
226-
...(renamed ? { name: trimmedName } : {}),
227221
...(typeChanged ? { type: typeInput } : {}),
228222
...(uniqueChanged ? { unique: uniqueInput } : {}),
229223
...(uniqueCleared ? { unique: false } : {}),
@@ -242,8 +236,7 @@ function ColumnConfigBody({
242236
}
243237

244238
await updateColumn.mutateAsync({ columnName: config.columnName, updates })
245-
if (renamed) onColumnRename?.(config.columnName, trimmedName)
246-
toast.success(`Saved "${trimmedName}"`)
239+
toast.success(`Saved "${existingColumn?.name ?? config.columnName}"`)
247240
onClose()
248241
} catch (err) {
249242
if (isValidationError(err)) {
@@ -276,23 +269,25 @@ function ColumnConfigBody({
276269
</div>
277270

278271
<div className='flex-1 overflow-y-auto overflow-x-hidden px-2 pt-3 pb-2 [overflow-anchor:none]'>
279-
<div className='flex flex-col gap-[9.5px]'>
280-
<RequiredLabel htmlFor='column-sidebar-name'>Column name</RequiredLabel>
281-
<ChipInput
282-
id='column-sidebar-name'
283-
value={nameInput}
284-
onChange={(e) => {
285-
setNameInput(e.target.value)
286-
if (nameError) setNameError(null)
287-
}}
288-
spellCheck={false}
289-
autoComplete='off'
290-
error={Boolean((showValidation && !trimmedName) || nameError)}
291-
aria-invalid={(showValidation && !trimmedName) || nameError ? true : undefined}
292-
/>
293-
{showValidation && !trimmedName && <FieldError message='Column name is required' />}
294-
{nameError && !(showValidation && !trimmedName) && <FieldError message={nameError} />}
295-
</div>
272+
{config.mode === 'create' && (
273+
<div className='flex flex-col gap-[9.5px]'>
274+
<RequiredLabel htmlFor='column-sidebar-name'>Column name</RequiredLabel>
275+
<ChipInput
276+
id='column-sidebar-name'
277+
value={nameInput}
278+
onChange={(e) => {
279+
setNameInput(e.target.value)
280+
if (nameError) setNameError(null)
281+
}}
282+
spellCheck={false}
283+
autoComplete='off'
284+
error={Boolean((showValidation && !trimmedName) || nameError)}
285+
aria-invalid={(showValidation && !trimmedName) || nameError ? true : undefined}
286+
/>
287+
{showValidation && !trimmedName && <FieldError message='Column name is required' />}
288+
{nameError && !(showValidation && !trimmedName) && <FieldError message={nameError} />}
289+
</div>
290+
)}
296291

297292
{config.mode === 'edit' && (
298293
<>

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/table.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,9 +313,9 @@ export function Table({
313313
}, [])
314314

315315
/**
316-
* Sink populated by the grid: invoked from sidebar `onColumnRename` so the
317-
* grid can rewrite its local `columnWidths` / `columnOrder` keys after a
318-
* rename. The grid's render assigns to `current`; the wrapper forwards calls.
316+
* Sink populated by the grid: invoked from the workflow sidebar after a
317+
* rename so the grid can rewrite its local `columnWidths` / `columnOrder`
318+
* keys. The grid's render assigns to `current`; the wrapper forwards calls.
319319
*/
320320
const columnRenameSinkRef = useRef<((oldName: string, newName: string) => void) | null>(null)
321321
const onColumnRename = (oldName: string, newName: string) => {
@@ -1659,7 +1659,6 @@ export function Table({
16591659
}
16601660
workspaceId={workspaceId}
16611661
tableId={tableId}
1662-
onColumnRename={onColumnRename}
16631662
/>
16641663
<EnrichmentsSidebar
16651664
open={slideout.kind === 'enrichments'}

0 commit comments

Comments
 (0)