Skip to content

Commit 3e0b68a

Browse files
fix(tables): drop removed select options from cells instead of stale pills
When an option is deleted, cells that referenced it previously rendered a gray fallback pill labeled with the raw internal id. They now drop the orphaned id and fall back to empty ("None"). Editors seed their selection from the still- valid ids too, so editing/saving such a cell writes the cleaned value.
1 parent d06c399 commit 3e0b68a

4 files changed

Lines changed: 20 additions & 15 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { SelectOptionsEditor } from './select-options-editor'
2-
export { resolveSelectOptions, SelectPill, toSelectedIds } from './select-pill'
2+
export { resolveSelectOptions, SelectPill, selectedOptionIds, toSelectedIds } from './select-pill'
33
export { SelectValueEditor } from './select-value-editor'

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/select-field/select-pill.tsx

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,29 @@
33
import { Badge, cn } from '@sim/emcn'
44
import type { ColumnDefinition, SelectOption } from '@/lib/table'
55

6-
/** Reads the selected option ids from a stored cell value of either select type. */
6+
/** Reads the raw stored option ids from a cell value (single string or array). */
77
export function toSelectedIds(value: unknown): string[] {
88
if (Array.isArray(value)) return value.filter((v): v is string => typeof v === 'string')
99
if (typeof value === 'string' && value !== '') return [value]
1010
return []
1111
}
1212

1313
/**
14-
* Resolves the stored ids of a `select`/`multiselect` cell to their declared
15-
* options, preserving selection order. An id with no matching option (stale
16-
* after an option was deleted) resolves to a neutral gray fallback so the cell
17-
* never renders blank.
14+
* Resolves a `select` cell's stored ids to their declared options, preserving
15+
* selection order. An id with no matching option stale after that option was
16+
* deleted — is dropped, so the cell falls back to empty ("None") rather than
17+
* showing an orphaned reference.
1818
*/
1919
export function resolveSelectOptions(column: ColumnDefinition, value: unknown): SelectOption[] {
20-
const options = column.options ?? []
21-
return toSelectedIds(value).map(
22-
(id) => options.find((o) => o.id === id) ?? { id, name: id, color: 'gray' }
23-
)
20+
const byId = new Map((column.options ?? []).map((o) => [o.id, o]))
21+
return toSelectedIds(value)
22+
.map((id) => byId.get(id))
23+
.filter((o): o is SelectOption => o != null)
24+
}
25+
26+
/** The still-valid option ids of a cell (orphaned/removed ids dropped). */
27+
export function selectedOptionIds(column: ColumnDefinition, value: unknown): string[] {
28+
return resolveSelectOptions(column, value).map((o) => o.id)
2429
}
2530

2631
interface SelectPillProps {

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/select-field/select-value-editor.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { useMemo } from 'react'
44
import { ChipDropdown } from '@sim/emcn'
55
import type { ColumnDefinition } from '@/lib/table'
6-
import { SelectPill, toSelectedIds } from './select-pill'
6+
import { SelectPill, selectedOptionIds } from './select-pill'
77

88
interface SelectValueEditorProps {
99
column: ColumnDefinition
@@ -43,7 +43,7 @@ export function SelectValueEditor({
4343
return (
4444
<ChipDropdown
4545
multiple
46-
value={toSelectedIds(value)}
46+
value={selectedOptionIds(column, value)}
4747
// A required multiselect can't be emptied — ignore the toggle that would
4848
// remove the last option, since an empty selection can never be committed.
4949
onChange={(ids) => {
@@ -71,7 +71,7 @@ export function SelectValueEditor({
7171

7272
return (
7373
<ChipDropdown
74-
value={toSelectedIds(value)[0] ?? CLEAR_VALUE}
74+
value={selectedOptionIds(column, value)[0] ?? CLEAR_VALUE}
7575
onChange={(id) => onChange(id === CLEAR_VALUE ? null : id)}
7676
options={singleOptions}
7777
placeholder='Select an option'

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/table-grid/cells/inline-editors.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
storageToDisplay,
2727
todayLocalCalendarDate,
2828
} from '../../../utils'
29-
import { SelectPill, toSelectedIds } from '../../select-field'
29+
import { SelectPill, selectedOptionIds } from '../../select-field'
3030

3131
interface InlineEditorProps {
3232
value: unknown
@@ -346,7 +346,7 @@ function InlineTextEditor({
346346
function InlineSelectEditor({ value, column, onSave, onCancel }: InlineEditorProps) {
347347
const isMulti = !!column.multiple
348348
const allOptions = column.options ?? []
349-
const [draft, setDraft] = useState<string[]>(() => toSelectedIds(value))
349+
const [draft, setDraft] = useState<string[]>(() => selectedOptionIds(column, value))
350350
const [open, setOpen] = useState(true)
351351
const latestRef = useRef(draft)
352352
const doneRef = useRef(false)

0 commit comments

Comments
 (0)