Skip to content

Commit d815568

Browse files
committed
improvement: tables, chat
1 parent 5dc026c commit d815568

File tree

12 files changed

+239
-131
lines changed

12 files changed

+239
-131
lines changed

apps/sim/app/api/table/[tableId]/rows/[rowId]/route.ts

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { z } from 'zod'
77
import { checkSessionOrInternalAuth } from '@/lib/auth/hybrid'
88
import { generateRequestId } from '@/lib/core/utils/request'
99
import type { RowData } from '@/lib/table'
10-
import { updateRow } from '@/lib/table'
10+
import { deleteRow, updateRow } from '@/lib/table'
1111
import { accessError, checkAccess } from '@/app/api/table/utils'
1212

1313
const logger = createLogger('TableRowAPI')
@@ -243,22 +243,7 @@ export async function DELETE(request: NextRequest, { params }: RowRouteParams) {
243243
return NextResponse.json({ error: 'Invalid workspace ID' }, { status: 400 })
244244
}
245245

246-
const [deletedRow] = await db
247-
.delete(userTableRows)
248-
.where(
249-
and(
250-
eq(userTableRows.id, rowId),
251-
eq(userTableRows.tableId, tableId),
252-
eq(userTableRows.workspaceId, validated.workspaceId)
253-
)
254-
)
255-
.returning()
256-
257-
if (!deletedRow) {
258-
return NextResponse.json({ error: 'Row not found' }, { status: 404 })
259-
}
260-
261-
logger.info(`[${requestId}] Deleted row ${rowId} from table ${tableId}`)
246+
await deleteRow(tableId, rowId, validated.workspaceId, requestId)
262247

263248
return NextResponse.json({
264249
success: true,
@@ -275,6 +260,12 @@ export async function DELETE(request: NextRequest, { params }: RowRouteParams) {
275260
)
276261
}
277262

263+
const errorMessage = error instanceof Error ? error.message : String(error)
264+
265+
if (errorMessage === 'Row not found') {
266+
return NextResponse.json({ error: errorMessage }, { status: 404 })
267+
}
268+
278269
logger.error(`[${requestId}] Error deleting row:`, error)
279270
return NextResponse.json({ error: 'Failed to delete row' }, { status: 500 })
280271
}

apps/sim/app/workspace/[workspaceId]/files/files.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export function Files() {
166166
const [creatingFile, setCreatingFile] = useState(false)
167167
const [isDirty, setIsDirty] = useState(false)
168168
const [saveStatus, setSaveStatus] = useState<SaveStatus>('idle')
169-
const [showPreview, setShowPreview] = useState(false)
169+
const [showPreview, setShowPreview] = useState(true)
170170
const [showUnsavedChangesAlert, setShowUnsavedChangesAlert] = useState(false)
171171
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
172172
const [contextMenuFile, setContextMenuFile] = useState<WorkspaceFileRecord | null>(null)
@@ -410,6 +410,7 @@ export function Files() {
410410
if (justCreatedFileIdRef.current && selectedFileId !== justCreatedFileIdRef.current) {
411411
justCreatedFileIdRef.current = null
412412
}
413+
setShowPreview(true)
413414
}, [selectedFileId])
414415

415416
useEffect(() => {

apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,18 @@ function mapStoredMessage(msg: TaskStoredMessage): ChatMessage {
100100
}
101101

102102
if (Array.isArray(msg.toolCalls) && msg.toolCalls.length > 0) {
103-
mapped.contentBlocks = msg.toolCalls.map(mapStoredToolCall)
103+
const blocks: ContentBlock[] = msg.toolCalls.map(mapStoredToolCall)
104+
if (msg.content?.trim()) {
105+
blocks.push({ type: 'text', content: msg.content })
106+
}
107+
mapped.contentBlocks = blocks
104108
} else if (Array.isArray(msg.contentBlocks) && msg.contentBlocks.length > 0) {
105-
mapped.contentBlocks = msg.contentBlocks.map(mapStoredBlock)
109+
const blocks = msg.contentBlocks.map(mapStoredBlock)
110+
const hasText = blocks.some((b) => b.type === 'text' && b.content?.trim())
111+
if (!hasText && msg.content?.trim()) {
112+
blocks.push({ type: 'text', content: msg.content })
113+
}
114+
mapped.contentBlocks = blocks
106115
}
107116

108117
return mapped

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

Lines changed: 43 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,36 @@
1-
import { ArrowDown, ArrowUp, Edit, Trash2 } from 'lucide-react'
2-
import {
3-
Popover,
4-
PopoverAnchor,
5-
PopoverContent,
6-
PopoverDivider,
7-
PopoverItem,
8-
} from '@/components/emcn'
1+
import { Popover, PopoverAnchor, PopoverContent } from '@/components/emcn'
2+
import { ArrowDown, ArrowUp, Pencil, Trash } from '@/components/emcn/icons'
3+
import { cn } from '@/lib/core/utils/cn'
94
import type { ContextMenuState } from '../../types'
105

6+
const MENU_ITEM =
7+
'relative flex cursor-default select-none items-center gap-[8px] rounded-[5px] px-[8px] py-[5px] font-medium text-[12px] text-[var(--text-secondary)] outline-none transition-colors hover:bg-[var(--surface-4)] hover:text-[var(--text-primary)] [&_svg]:pointer-events-none [&_svg]:size-[14px] [&_svg]:shrink-0'
8+
9+
const MENU_SEPARATOR = '-mx-[6px] my-[6px] h-px bg-[var(--border-1)]'
10+
1111
interface ContextMenuProps {
1212
contextMenu: ContextMenuState
1313
onClose: () => void
14-
onEdit: () => void
14+
onEditCell: () => void
1515
onDelete: () => void
1616
onInsertAbove: () => void
1717
onInsertBelow: () => void
18+
selectedRowCount?: number
1819
}
1920

2021
export function ContextMenu({
2122
contextMenu,
2223
onClose,
23-
onEdit,
24+
onEditCell,
2425
onDelete,
2526
onInsertAbove,
2627
onInsertBelow,
28+
selectedRowCount = 1,
2729
}: ContextMenuProps) {
30+
const deleteLabel = selectedRowCount > 1 ? `Delete ${selectedRowCount} rows` : 'Delete row'
31+
2832
return (
29-
<Popover
30-
open={contextMenu.isOpen}
31-
onOpenChange={(open) => !open && onClose()}
32-
variant='secondary'
33-
size='sm'
34-
colorScheme='inverted'
35-
>
33+
<Popover open={contextMenu.isOpen} onOpenChange={(open) => !open && onClose()}>
3634
<PopoverAnchor
3735
style={{
3836
position: 'fixed',
@@ -42,24 +40,36 @@ export function ContextMenu({
4240
height: '1px',
4341
}}
4442
/>
45-
<PopoverContent align='start' side='bottom' sideOffset={4}>
46-
<PopoverItem onClick={onEdit}>
47-
<Edit className='mr-[8px] h-[12px] w-[12px]' />
48-
Edit row
49-
</PopoverItem>
50-
<PopoverItem onClick={onInsertAbove}>
51-
<ArrowUp className='mr-[8px] h-[12px] w-[12px]' />
43+
<PopoverContent
44+
align='start'
45+
side='bottom'
46+
sideOffset={4}
47+
border
48+
className='!min-w-[160px] !rounded-[8px] !bg-[var(--bg)] !p-[6px] shadow-sm'
49+
>
50+
{contextMenu.columnName && (
51+
<div className={MENU_ITEM} onClick={onEditCell} role='menuitem'>
52+
<Pencil />
53+
Edit cell
54+
</div>
55+
)}
56+
<div className={MENU_ITEM} onClick={onInsertAbove} role='menuitem'>
57+
<ArrowUp />
5258
Insert row above
53-
</PopoverItem>
54-
<PopoverItem onClick={onInsertBelow}>
55-
<ArrowDown className='mr-[8px] h-[12px] w-[12px]' />
59+
</div>
60+
<div className={MENU_ITEM} onClick={onInsertBelow} role='menuitem'>
61+
<ArrowDown />
5662
Insert row below
57-
</PopoverItem>
58-
<PopoverDivider />
59-
<PopoverItem onClick={onDelete} className='text-[var(--text-error)]'>
60-
<Trash2 className='mr-[8px] h-[12px] w-[12px]' />
61-
Delete row
62-
</PopoverItem>
63+
</div>
64+
<div className={MENU_SEPARATOR} role='separator' />
65+
<div
66+
className={cn(MENU_ITEM, 'text-[var(--text-error)] hover:text-[var(--text-error)]')}
67+
onClick={onDelete}
68+
role='menuitem'
69+
>
70+
<Trash />
71+
{deleteLabel}
72+
</div>
6373
</PopoverContent>
6474
</Popover>
6575
)

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

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import { useState } from 'react'
44
import { createLogger } from '@sim/logger'
5-
import { AlertCircle } from 'lucide-react'
65
import { useParams } from 'next/navigation'
76
import {
87
Button,
@@ -148,50 +147,32 @@ export function RowModal({ mode, isOpen, onClose, table, row, rowIds, onSuccess
148147
onClose()
149148
}
150149

151-
// Delete mode UI
152150
if (mode === 'delete') {
153151
const deleteCount = rowIds?.length ?? (row ? 1 : 0)
154152
const isSingleRow = deleteCount === 1
155153

156154
return (
157155
<Modal open={isOpen} onOpenChange={handleClose}>
158-
<ModalContent className='w-[480px]'>
159-
<ModalHeader>
160-
<div className='flex items-center gap-[10px]'>
161-
<div className='flex h-[36px] w-[36px] items-center justify-center rounded-[8px] bg-[var(--bg-error)] text-[var(--text-error)]'>
162-
<AlertCircle className='h-[18px] w-[18px]' />
163-
</div>
164-
<h2 className='font-semibold text-[16px]'>
165-
Delete {isSingleRow ? 'Row' : `${deleteCount} Rows`}
166-
</h2>
167-
</div>
168-
</ModalHeader>
156+
<ModalContent size='sm'>
157+
<ModalHeader>Delete {isSingleRow ? 'Row' : `${deleteCount} Rows`}</ModalHeader>
169158
<ModalBody>
170-
<div className='flex flex-col gap-[16px]'>
171-
<ErrorMessage error={error} />
172-
<p className='text-[14px] text-[var(--text-secondary)]'>
173-
Are you sure you want to delete {isSingleRow ? 'this row' : 'these rows'}? This
174-
action cannot be undone.
175-
</p>
176-
</div>
159+
{error && (
160+
<div className='rounded-[8px] border border-[var(--status-error-border)] bg-[var(--status-error-bg)] px-[14px] py-[12px] text-[13px] text-[var(--status-error-text)]'>
161+
{error}
162+
</div>
163+
)}
164+
<p className='text-[12px] text-[var(--text-secondary)]'>
165+
Are you sure you want to delete{' '}
166+
{isSingleRow ? 'this row' : `these ${deleteCount} rows`}? This will permanently remove
167+
all data in {isSingleRow ? 'this row' : 'these rows'}.{' '}
168+
<span className='text-[var(--text-error)]'>This action cannot be undone.</span>
169+
</p>
177170
</ModalBody>
178-
<ModalFooter className='gap-[10px]'>
179-
<Button
180-
type='button'
181-
variant='default'
182-
onClick={handleClose}
183-
className='min-w-[90px]'
184-
disabled={isSubmitting}
185-
>
171+
<ModalFooter>
172+
<Button variant='default' onClick={handleClose} disabled={isSubmitting}>
186173
Cancel
187174
</Button>
188-
<Button
189-
type='button'
190-
variant='destructive'
191-
onClick={handleDelete}
192-
disabled={isSubmitting}
193-
className='min-w-[120px]'
194-
>
175+
<Button variant='destructive' onClick={handleDelete} disabled={isSubmitting}>
195176
{isSubmitting ? 'Deleting...' : 'Delete'}
196177
</Button>
197178
</ModalFooter>

0 commit comments

Comments
 (0)