Skip to content

Commit 603f1c2

Browse files
authored
improvement(tables): simplify column dropdown (#7193)
1 parent 57235de commit 603f1c2

9 files changed

Lines changed: 88 additions & 33 deletions

File tree

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import { ALL_COLUMN_TYPES } from '@/lib/table/column-types'
88
* "+ New column" dropdown to spawn a workflow group; the resulting columns are
99
* stored as scalar types under the hood (none carry `'workflow'`).
1010
*/
11-
export type SidebarColumnType = ColumnDefinition['type'] | 'workflow'
11+
type SidebarColumnType = ColumnDefinition['type'] | 'workflow'
1212

13-
export interface ColumnTypeOption {
13+
interface ColumnTypeOption {
1414
type: SidebarColumnType
1515
label: string
1616
icon: React.ComponentType<{ className?: string }>
Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
11
export type { ColumnConfig } from './column-config-sidebar'
22
export { ColumnConfigSidebar } from './column-config-sidebar'
3-
export {
4-
COLUMN_TYPE_OPTIONS,
5-
type ColumnTypeOption,
6-
PLAIN_COLUMN_TYPE_OPTIONS,
7-
type SidebarColumnType,
8-
} from './column-types'
3+
export { COLUMN_TYPE_OPTIONS, PLAIN_COLUMN_TYPE_OPTIONS } from './column-types'
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* @vitest-environment jsdom
3+
*/
4+
import { act } from 'react'
5+
import { createRoot, type Root } from 'react-dom/client'
6+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
7+
import { COLUMN_TYPE_OPTIONS } from '@/app/workspace/[workspaceId]/tables/[tableId]/components/column-config-sidebar'
8+
import { ColumnDropdown } from '@/app/workspace/[workspaceId]/tables/[tableId]/components/column-dropdown/column-dropdown'
9+
10+
let container: HTMLDivElement
11+
let root: Root
12+
13+
beforeEach(() => {
14+
globalThis.IS_REACT_ACT_ENVIRONMENT = true
15+
container = document.createElement('div')
16+
document.body.appendChild(container)
17+
root = createRoot(container)
18+
})
19+
20+
afterEach(() => {
21+
act(() => root.unmount())
22+
container.remove()
23+
})
24+
25+
describe('ColumnDropdown', () => {
26+
it('lists Enrichments as a regular entry after the column options', () => {
27+
const onPickEnrichment = vi.fn()
28+
29+
act(() => {
30+
root.render(
31+
<ColumnDropdown
32+
trigger='header'
33+
disabled={false}
34+
onPickType={vi.fn()}
35+
onPickWorkflow={vi.fn()}
36+
onPickEnrichment={onPickEnrichment}
37+
blocked={false}
38+
onBlocked={vi.fn()}
39+
/>
40+
)
41+
})
42+
act(() => {
43+
container
44+
.querySelector<HTMLButtonElement>('button')
45+
?.dispatchEvent(new MouseEvent('pointerdown', { bubbles: true, button: 0 }))
46+
})
47+
48+
const items = [...document.body.querySelectorAll<HTMLElement>('[role="menuitem"]')]
49+
expect(items.map((item) => item.textContent)).toEqual([
50+
...COLUMN_TYPE_OPTIONS.map((option) => option.label),
51+
'Enrichments',
52+
])
53+
expect(document.body.querySelector('[role="separator"]')).toBeNull()
54+
55+
act(() => items.at(-1)?.click())
56+
expect(onPickEnrichment).toHaveBeenCalledOnce()
57+
})
58+
})

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/new-column-dropdown/new-column-dropdown.tsx renamed to apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/column-dropdown/column-dropdown.tsx

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
DropdownMenu,
99
DropdownMenuContent,
1010
DropdownMenuItem,
11-
DropdownMenuSeparator,
1211
DropdownMenuTrigger,
1312
Plus,
1413
} from '@sim/emcn'
@@ -19,7 +18,7 @@ import { COLUMN_TYPE_OPTIONS } from '../column-config-sidebar'
1918
const CELL_HEADER =
2019
'border-[var(--border)] border-r border-b bg-[var(--bg)] px-2 py-[7px] text-left align-middle'
2120

22-
interface NewColumnDropdownProps {
21+
interface ColumnDropdownProps {
2322
/** `'header'` renders the page-header trigger (subtle Button); `'inline-header'` renders
2423
* the in-table column-header `<th>` trigger. Same dropdown content either way. */
2524
trigger: 'header' | 'inline-header'
@@ -42,15 +41,15 @@ interface NewColumnDropdownProps {
4241
* Lists every column type plus "Workflow" and "Enrichments"; picking a type
4342
* opens the right sidebar pre-seeded.
4443
*/
45-
export function NewColumnDropdown({
44+
export function ColumnDropdown({
4645
trigger,
4746
disabled,
4847
onPickType,
4948
onPickWorkflow,
5049
onPickEnrichment,
5150
blocked,
5251
onBlocked,
53-
}: NewColumnDropdownProps) {
52+
}: ColumnDropdownProps) {
5453
const triggerButton =
5554
trigger === 'header' ? (
5655
<button
@@ -86,18 +85,7 @@ export function NewColumnDropdown({
8685
const menu = (
8786
<DropdownMenu>
8887
<DropdownMenuTrigger asChild>{triggerButton}</DropdownMenuTrigger>
89-
{/* Taller than the 240px shared default: the full type list is 9 items
90-
(295px with its separator and padding), so the default cut the last
91-
two off behind a scrollbar. Sized here rather than in the shared
92-
component, which every other dropdown in the app relies on. */}
93-
<DropdownMenuContent align='start' side='bottom' sideOffset={4} className='max-h-[320px]'>
94-
<>
95-
<DropdownMenuItem onSelect={onPickEnrichment}>
96-
<Sparkles className='size-[14px] text-[var(--text-icon)]' />
97-
Enrichments
98-
</DropdownMenuItem>
99-
<DropdownMenuSeparator />
100-
</>
88+
<DropdownMenuContent align='start' side='bottom' sideOffset={4}>
10189
{COLUMN_TYPE_OPTIONS.map((option) => {
10290
const Icon = option.icon
10391
const onSelect =
@@ -111,6 +99,10 @@ export function NewColumnDropdown({
11199
</DropdownMenuItem>
112100
)
113101
})}
102+
<DropdownMenuItem onSelect={onPickEnrichment}>
103+
<Sparkles className='size-[14px] text-[var(--text-icon)]' />
104+
Enrichments
105+
</DropdownMenuItem>
114106
</DropdownMenuContent>
115107
</DropdownMenu>
116108
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { ColumnDropdown } from './column-dropdown'

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
export * from './column-config-sidebar'
2+
export * from './column-dropdown'
23
export * from './columns-menu'
34
export * from './context-menu'
45
export * from './enrichment-details'
56
export * from './enrichments-sidebar'
67
export * from './lock-settings-modal'
7-
export * from './new-column-dropdown'
88
export * from './row-modal'
99
export * from './run-status-control'
1010
export * from './save-view-modal'

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/new-column-dropdown/index.ts

Lines changed: 0 additions & 1 deletion
This file was deleted.

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

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ import { useContextMenu, useTable } from '../../hooks'
5757
import type { EditingCell, QueryOptions, SaveReason } from '../../types'
5858
import { cleanCellValue, generateColumnName as sharedGenerateColumnName } from '../../utils'
5959
import type { ColumnConfig } from '../column-config-sidebar'
60+
import { ColumnDropdown } from '../column-dropdown'
6061
import { ContextMenu } from '../context-menu'
61-
import { NewColumnDropdown } from '../new-column-dropdown'
6262
import type { WorkflowConfig } from '../workflow-sidebar'
6363
import { ExpandedCellPopover } from './cells'
6464
import { ADD_COL_WIDTH, COL_WIDTH, SELECTION_TINT_BG } from './constants'
@@ -898,7 +898,11 @@ export function TableGrid({
898898
* so solo editing never pays the map build. */
899899
const columnIndexById = useMemo(() => {
900900
const map = new Map<string, number>()
901-
if (remoteSelections.length > 0) displayColumns.forEach((col, index) => map.set(col.key, index))
901+
if (remoteSelections.length > 0) {
902+
displayColumns.forEach((col, index) => {
903+
map.set(col.key, index)
904+
})
905+
}
902906
return map
903907
}, [displayColumns, remoteSelections.length])
904908

@@ -907,7 +911,11 @@ export function TableGrid({
907911
* solo editing never pays the O(n) map build on a refetch. */
908912
const rowIndexById = useMemo(() => {
909913
const map = new Map<string, number>()
910-
if (remoteSelections.length > 0) rows.forEach((row, index) => map.set(row.id, index))
914+
if (remoteSelections.length > 0) {
915+
rows.forEach((row, index) => {
916+
map.set(row.id, index)
917+
})
918+
}
911919
return map
912920
}, [rows, remoteSelections.length])
913921

@@ -2251,7 +2259,9 @@ export function TableGrid({
22512259
const draggedGid = colByName.get(dragged)?.workflowGroupId
22522260

22532261
const orderIndex = new Map<string, number>()
2254-
currentOrder.forEach((n, i) => orderIndex.set(n, i))
2262+
currentOrder.forEach((n, i) => {
2263+
orderIndex.set(n, i)
2264+
})
22552265

22562266
// Compute the contiguous run covering the dragged column. For a plain
22572267
// column this is just [fromIndex, fromIndex]. For a group member it spans
@@ -4853,7 +4863,7 @@ export function TableGrid({
48534863
)
48544864
})}
48554865
{userPermissions.canEdit && (
4856-
<NewColumnDropdown
4866+
<ColumnDropdown
48574867
trigger='inline-header'
48584868
disabled={addColumnMutation.isPending}
48594869
blocked={!canMutateSchema}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ import type { DeletedRowSnapshot } from '@/stores/table/types'
7171
import {
7272
type ColumnConfig,
7373
ColumnConfigSidebar,
74+
ColumnDropdown,
7475
ColumnsMenu,
7576
EnrichmentDetails,
7677
EnrichmentsSidebar,
7778
LockSettingsModal,
78-
NewColumnDropdown,
7979
RowModal,
8080
RunStatusControl,
8181
SaveViewModal,
@@ -1372,7 +1372,7 @@ export function Table({
13721372
// table is schema-locked and explains itself instead of disappearing.
13731373
const canMutateSchema = userPermissions.canEdit && !tableData?.locks.schemaLocked
13741374
const createTrigger = userPermissions.canEdit ? (
1375-
<NewColumnDropdown
1375+
<ColumnDropdown
13761376
trigger='header'
13771377
disabled={false}
13781378
blocked={!canMutateSchema}

0 commit comments

Comments
 (0)