Skip to content

Commit 2f5191d

Browse files
committed
improvement(tables): ops and experience
1 parent d885892 commit 2f5191d

File tree

36 files changed

+1307
-576
lines changed

36 files changed

+1307
-576
lines changed

apps/sim/app/api/schedules/execute/route.test.ts

Lines changed: 23 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
*
44
* @vitest-environment node
55
*/
6-
import type { NextRequest } from 'next/server'
6+
import { createFeatureFlagsMock, createMockRequest } from '@sim/testing'
7+
import { drizzleOrmMock } from '@sim/testing/mocks'
78
import { beforeEach, describe, expect, it, vi } from 'vitest'
89

910
const {
1011
mockVerifyCronAuth,
1112
mockExecuteScheduleJob,
1213
mockExecuteJobInline,
13-
mockFeatureFlags,
1414
mockDbReturning,
1515
mockDbUpdate,
1616
mockEnqueue,
@@ -33,12 +33,6 @@ const {
3333
mockVerifyCronAuth: vi.fn().mockReturnValue(null),
3434
mockExecuteScheduleJob: vi.fn().mockResolvedValue(undefined),
3535
mockExecuteJobInline: vi.fn().mockResolvedValue(undefined),
36-
mockFeatureFlags: {
37-
isTriggerDevEnabled: false,
38-
isHosted: false,
39-
isProd: false,
40-
isDev: true,
41-
},
4236
mockDbReturning,
4337
mockDbUpdate,
4438
mockEnqueue,
@@ -49,6 +43,13 @@ const {
4943
}
5044
})
5145

46+
const mockFeatureFlags = createFeatureFlagsMock({
47+
isTriggerDevEnabled: false,
48+
isHosted: false,
49+
isProd: false,
50+
isDev: true,
51+
})
52+
5253
vi.mock('@/lib/auth/internal', () => ({
5354
verifyCronAuth: mockVerifyCronAuth,
5455
}))
@@ -91,17 +92,7 @@ vi.mock('@/lib/workflows/utils', () => ({
9192
}),
9293
}))
9394

94-
vi.mock('drizzle-orm', () => ({
95-
and: vi.fn((...conditions: unknown[]) => ({ type: 'and', conditions })),
96-
eq: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'eq' })),
97-
ne: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'ne' })),
98-
lte: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'lte' })),
99-
lt: vi.fn((field: unknown, value: unknown) => ({ field, value, type: 'lt' })),
100-
not: vi.fn((condition: unknown) => ({ type: 'not', condition })),
101-
isNull: vi.fn((field: unknown) => ({ type: 'isNull', field })),
102-
or: vi.fn((...conditions: unknown[]) => ({ type: 'or', conditions })),
103-
sql: vi.fn((strings: unknown, ...values: unknown[]) => ({ type: 'sql', strings, values })),
104-
}))
95+
vi.mock('drizzle-orm', () => drizzleOrmMock)
10596

10697
vi.mock('@sim/db', () => ({
10798
db: {
@@ -177,18 +168,13 @@ const SINGLE_JOB = [
177168
},
178169
]
179170

180-
function createMockRequest(): NextRequest {
181-
const mockHeaders = new Map([
182-
['authorization', 'Bearer test-cron-secret'],
183-
['content-type', 'application/json'],
184-
])
185-
186-
return {
187-
headers: {
188-
get: (key: string) => mockHeaders.get(key.toLowerCase()) || null,
189-
},
190-
url: 'http://localhost:3000/api/schedules/execute',
191-
} as NextRequest
171+
function createCronRequest() {
172+
return createMockRequest(
173+
'GET',
174+
undefined,
175+
{ Authorization: 'Bearer test-cron-secret' },
176+
'http://localhost:3000/api/schedules/execute'
177+
)
192178
}
193179

194180
describe('Scheduled Workflow Execution API Route', () => {
@@ -204,7 +190,7 @@ describe('Scheduled Workflow Execution API Route', () => {
204190
it('should execute scheduled workflows with Trigger.dev disabled', async () => {
205191
mockDbReturning.mockReturnValueOnce(SINGLE_SCHEDULE).mockReturnValueOnce([])
206192

207-
const response = await GET(createMockRequest())
193+
const response = await GET(createCronRequest() as any)
208194

209195
expect(response).toBeDefined()
210196
expect(response.status).toBe(200)
@@ -217,7 +203,7 @@ describe('Scheduled Workflow Execution API Route', () => {
217203
mockFeatureFlags.isTriggerDevEnabled = true
218204
mockDbReturning.mockReturnValueOnce(SINGLE_SCHEDULE).mockReturnValueOnce([])
219205

220-
const response = await GET(createMockRequest())
206+
const response = await GET(createCronRequest() as any)
221207

222208
expect(response).toBeDefined()
223209
expect(response.status).toBe(200)
@@ -228,7 +214,7 @@ describe('Scheduled Workflow Execution API Route', () => {
228214
it('should handle case with no due schedules', async () => {
229215
mockDbReturning.mockReturnValueOnce([]).mockReturnValueOnce([])
230216

231-
const response = await GET(createMockRequest())
217+
const response = await GET(createCronRequest() as any)
232218

233219
expect(response.status).toBe(200)
234220
const data = await response.json()
@@ -239,7 +225,7 @@ describe('Scheduled Workflow Execution API Route', () => {
239225
it('should execute multiple schedules in parallel', async () => {
240226
mockDbReturning.mockReturnValueOnce(MULTIPLE_SCHEDULES).mockReturnValueOnce([])
241227

242-
const response = await GET(createMockRequest())
228+
const response = await GET(createCronRequest() as any)
243229

244230
expect(response.status).toBe(200)
245231
const data = await response.json()
@@ -249,7 +235,7 @@ describe('Scheduled Workflow Execution API Route', () => {
249235
it('should queue mothership jobs to BullMQ when available', async () => {
250236
mockDbReturning.mockReturnValueOnce([]).mockReturnValueOnce(SINGLE_JOB)
251237

252-
const response = await GET(createMockRequest())
238+
const response = await GET(createCronRequest() as any)
253239

254240
expect(response.status).toBe(200)
255241
expect(mockEnqueueWorkspaceDispatch).toHaveBeenCalledWith(
@@ -274,7 +260,7 @@ describe('Scheduled Workflow Execution API Route', () => {
274260
it('should enqueue preassigned correlation metadata for schedules', async () => {
275261
mockDbReturning.mockReturnValue(SINGLE_SCHEDULE)
276262

277-
const response = await GET(createMockRequest())
263+
const response = await GET(createCronRequest() as any)
278264

279265
expect(response.status).toBe(200)
280266
expect(mockEnqueueWorkspaceDispatch).toHaveBeenCalledWith(

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/context-menu/context-menu.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
DropdownMenuTrigger,
77
} from '@/components/emcn'
88
import { ArrowDown, ArrowUp, Duplicate, Pencil, Trash } from '@/components/emcn/icons'
9-
import type { ContextMenuState } from '../../types'
9+
import type { ContextMenuState } from '@/app/workspace/[workspaceId]/tables/[tableId]/types'
1010

1111
interface ContextMenuProps {
1212
contextMenu: ContextMenuState

apps/sim/app/workspace/[workspaceId]/tables/[tableId]/components/row-modal/row-modal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,16 @@ import {
1717
Textarea,
1818
} from '@/components/emcn'
1919
import type { ColumnDefinition, TableInfo, TableRow } from '@/lib/table'
20+
import {
21+
cleanCellValue,
22+
formatValueForInput,
23+
} from '@/app/workspace/[workspaceId]/tables/[tableId]/utils'
2024
import {
2125
useCreateTableRow,
2226
useDeleteTableRow,
2327
useDeleteTableRows,
2428
useUpdateTableRow,
2529
} from '@/hooks/queries/tables'
26-
import { cleanCellValue, formatValueForInput } from '../../utils'
2730

2831
const logger = createLogger('RowModal')
2932

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
export type { TableFilterHandle } from './table-filter'
12
export { TableFilter } from './table-filter'

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
'use client'
22

3-
import { memo, useCallback, useMemo, useRef, useState } from 'react'
3+
import {
4+
forwardRef,
5+
memo,
6+
useCallback,
7+
useImperativeHandle,
8+
useMemo,
9+
useRef,
10+
useState,
11+
} from 'react'
412
import { X } from 'lucide-react'
513
import { nanoid } from 'nanoid'
614
import {
@@ -19,22 +27,42 @@ const OPERATOR_LABELS = Object.fromEntries(
1927
COMPARISON_OPERATORS.map((op) => [op.value, op.label])
2028
) as Record<string, string>
2129

30+
export interface TableFilterHandle {
31+
addColumnRule: (columnName: string) => void
32+
}
33+
2234
interface TableFilterProps {
2335
columns: Array<{ name: string; type: string }>
2436
filter: Filter | null
2537
onApply: (filter: Filter | null) => void
2638
onClose: () => void
39+
initialColumn?: string | null
2740
}
2841

29-
export function TableFilter({ columns, filter, onApply, onClose }: TableFilterProps) {
42+
export const TableFilter = forwardRef<TableFilterHandle, TableFilterProps>(function TableFilter(
43+
{ columns, filter, onApply, onClose, initialColumn },
44+
ref
45+
) {
3046
const [rules, setRules] = useState<FilterRule[]>(() => {
3147
const fromFilter = filterToRules(filter)
32-
return fromFilter.length > 0 ? fromFilter : [createRule(columns)]
48+
if (fromFilter.length > 0) return fromFilter
49+
const rule = createRule(columns)
50+
return [initialColumn ? { ...rule, column: initialColumn } : rule]
3351
})
3452

3553
const rulesRef = useRef(rules)
3654
rulesRef.current = rules
3755

56+
useImperativeHandle(
57+
ref,
58+
() => ({
59+
addColumnRule: (columnName: string) => {
60+
setRules((prev) => [...prev, { ...createRule(columns), column: columnName }])
61+
},
62+
}),
63+
[columns]
64+
)
65+
3866
const columnOptions = useMemo(
3967
() => columns.map((col) => ({ value: col.name, label: col.name })),
4068
[columns]
@@ -125,7 +153,7 @@ export function TableFilter({ columns, filter, onApply, onClose }: TableFilterPr
125153
</div>
126154
</div>
127155
)
128-
}
156+
})
129157

130158
interface FilterRuleRowProps {
131159
rule: FilterRule

0 commit comments

Comments
 (0)