Skip to content

Commit a25eb83

Browse files
committed
fix(tables): keep sidebar renaming in reference foundation
1 parent 7d16f89 commit a25eb83

3 files changed

Lines changed: 45 additions & 25 deletions

File tree

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ function findButton(label: string): HTMLButtonElement | undefined {
104104
)
105105
}
106106

107+
function setInputValue(input: HTMLInputElement, value: string): void {
108+
const valueSetter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set
109+
valueSetter?.call(input, value)
110+
input.dispatchEvent(new Event('input', { bubbles: true }))
111+
}
112+
107113
beforeEach(() => {
108114
globalThis.IS_REACT_ACT_ENVIRONMENT = true
109115
container = document.createElement('div')
@@ -184,7 +190,8 @@ describe('ColumnConfigSidebar', () => {
184190
expect(mockUpdateColumn).not.toHaveBeenCalled()
185191
})
186192

187-
it('edits Reference configuration without exposing column renaming', async () => {
193+
it('edits a Reference column name and target table together', async () => {
194+
const onColumnRename = vi.fn()
188195
await act(async () => {
189196
root.render(
190197
<ColumnConfigSidebar
@@ -198,20 +205,26 @@ describe('ColumnConfigSidebar', () => {
198205
}}
199206
workspaceId='workspace-1'
200207
tableId='table-current'
208+
onColumnRename={onColumnRename}
201209
/>
202210
)
203211
})
204212

205-
expect(container).not.toHaveTextContent('Column name')
206-
expect(container.querySelector('#column-sidebar-name')).toBeNull()
213+
const nameInput = container.querySelector<HTMLInputElement>('#column-sidebar-name')
214+
expect(nameInput?.value).toBe('Related row')
207215

216+
act(() => setInputValue(nameInput!, 'Renamed relation'))
208217
act(() => findCombobox('Select table')?.onChange?.('table-customers'))
209218
await act(async () => findButton('Save')?.click())
210219

211220
expect(mockUpdateColumn).toHaveBeenCalledWith({
212221
columnName: 'col-reference',
213-
updates: { referenceTableId: 'table-customers' },
222+
updates: {
223+
name: 'Renamed relation',
224+
referenceTableId: 'table-customers',
225+
},
214226
})
227+
expect(onColumnRename).toHaveBeenCalledWith('col-reference', 'Renamed relation')
215228
})
216229

217230
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: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ interface ColumnConfigSidebarProps {
7676
readOnly?: boolean
7777
/** Why saving is unavailable; surfaced on the disabled Save button. */
7878
readOnlyReason?: string
79+
/** Notify parent of a rename so it can rewrite local `columnOrder` /
80+
* `columnWidths` keys that reference the old name. */
81+
onColumnRename?: (oldName: string, newName: string) => void
7982
}
8083

8184
/**
@@ -127,6 +130,7 @@ function ColumnConfigBody({
127130
tableId,
128131
readOnly,
129132
readOnlyReason,
133+
onColumnRename,
130134
}: ColumnConfigBodyProps) {
131135
const updateColumn = useUpdateColumn({ workspaceId, tableId })
132136
const addColumn = useAddTableColumn({ workspaceId, tableId })
@@ -189,7 +193,7 @@ function ColumnConfigBody({
189193
async function handleSave() {
190194
// Belt and braces: the button is disabled, and the server refuses too.
191195
if (readOnly) return
192-
if (config.mode === 'create' && !trimmedName) {
196+
if (!trimmedName) {
193197
setShowValidation(true)
194198
return
195199
}
@@ -221,6 +225,7 @@ function ColumnConfigBody({
221225
return
222226
}
223227

228+
const renamed = trimmedName !== (existingColumn?.name ?? config.columnName)
224229
const typeChanged = !!existingColumn && existingColumn.type !== typeInput
225230
const uniqueChanged =
226231
supportsUnique && !!existingColumn && !!existingColumn.unique !== uniqueInput
@@ -234,13 +239,15 @@ function ColumnConfigBody({
234239
wantsReference && existingColumn?.referenceTableId !== referenceTableInput
235240

236241
const updates: {
242+
name?: string
237243
type?: ColumnDefinition['type']
238244
unique?: boolean
239245
options?: SelectOption[]
240246
multiple?: boolean
241247
currencyCode?: string
242248
referenceTableId?: string
243249
} = {
250+
...(renamed ? { name: trimmedName } : {}),
244251
...(typeChanged ? { type: typeInput } : {}),
245252
...(uniqueChanged ? { unique: uniqueInput } : {}),
246253
...(uniqueCleared ? { unique: false } : {}),
@@ -259,7 +266,8 @@ function ColumnConfigBody({
259266
}
260267

261268
await updateColumn.mutateAsync({ columnName: config.columnName, updates })
262-
toast.success(`Saved "${existingColumn?.name ?? config.columnName}"`)
269+
if (renamed) onColumnRename?.(config.columnName, trimmedName)
270+
toast.success(`Saved "${trimmedName}"`)
263271
onClose()
264272
} catch (err) {
265273
if (isValidationError(err)) {
@@ -296,25 +304,23 @@ function ColumnConfigBody({
296304
including the comboboxes' trigger buttons; `contents` keeps the
297305
existing layout. Values stay readable and selectable. */}
298306
<fieldset disabled={readOnly} className='contents'>
299-
{config.mode === 'create' && (
300-
<div className='flex flex-col gap-[9.5px]'>
301-
<RequiredLabel htmlFor='column-sidebar-name'>Column name</RequiredLabel>
302-
<ChipInput
303-
id='column-sidebar-name'
304-
value={nameInput}
305-
onChange={(e) => {
306-
setNameInput(e.target.value)
307-
if (nameError) setNameError(null)
308-
}}
309-
spellCheck={false}
310-
autoComplete='off'
311-
error={Boolean((showValidation && !trimmedName) || nameError)}
312-
aria-invalid={(showValidation && !trimmedName) || nameError ? true : undefined}
313-
/>
314-
{showValidation && !trimmedName && <FieldError message='Column name is required' />}
315-
{nameError && !(showValidation && !trimmedName) && <FieldError message={nameError} />}
316-
</div>
317-
)}
307+
<div className='flex flex-col gap-[9.5px]'>
308+
<RequiredLabel htmlFor='column-sidebar-name'>Column name</RequiredLabel>
309+
<ChipInput
310+
id='column-sidebar-name'
311+
value={nameInput}
312+
onChange={(e) => {
313+
setNameInput(e.target.value)
314+
if (nameError) setNameError(null)
315+
}}
316+
spellCheck={false}
317+
autoComplete='off'
318+
error={Boolean((showValidation && !trimmedName) || nameError)}
319+
aria-invalid={(showValidation && !trimmedName) || nameError ? true : undefined}
320+
/>
321+
{showValidation && !trimmedName && <FieldError message='Column name is required' />}
322+
{nameError && !(showValidation && !trimmedName) && <FieldError message={nameError} />}
323+
</div>
318324

319325
{config.mode === 'edit' && (
320326
<>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1726,6 +1726,7 @@ export function Table({
17261726
? LOCK_TOOLTIPS.schema
17271727
: 'You don’t have permission to change columns.'
17281728
}
1729+
onColumnRename={onColumnRename}
17291730
/>
17301731
<EnrichmentsSidebar
17311732
open={slideout.kind === 'enrichments'}

0 commit comments

Comments
 (0)