Skip to content

Commit c1ee62f

Browse files
committed
address comments
1 parent 154aad1 commit c1ee62f

11 files changed

Lines changed: 177 additions & 110 deletions

File tree

apps/sim/app/api/mcp/servers/[id]/route.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,16 @@ import { updateMcpServerBodySchema } from '@/lib/api/contracts/mcp'
55
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
66
import { getParsedBody, withMcpAuth } from '@/lib/mcp/middleware'
77
import { performUpdateMcpServer } from '@/lib/mcp/orchestration'
8-
import { createMcpErrorResponse, createMcpSuccessResponse } from '@/lib/mcp/utils'
8+
import {
9+
createMcpErrorResponse,
10+
createMcpSuccessResponse,
11+
mcpOrchestrationStatus,
12+
} from '@/lib/mcp/utils'
913

1014
const logger = createLogger('McpServerAPI')
1115

1216
export const dynamic = 'force-dynamic'
1317

14-
function mcpOrchestrationStatus(errorCode: string | undefined): number {
15-
if (errorCode === 'forbidden') return 403
16-
if (errorCode === 'bad_gateway') return 502
17-
if (errorCode === 'not_found') return 404
18-
return 500
19-
}
20-
2118
/**
2219
* PATCH - Update an MCP server in the workspace (requires write or admin permission)
2320
*/

apps/sim/app/api/mcp/servers/route.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,16 @@ import { validationErrorResponse } from '@/lib/api/server'
99
import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
1010
import { getParsedBody, withMcpAuth } from '@/lib/mcp/middleware'
1111
import { performCreateMcpServer, performDeleteMcpServer } from '@/lib/mcp/orchestration'
12-
import { createMcpErrorResponse, createMcpSuccessResponse } from '@/lib/mcp/utils'
12+
import {
13+
createMcpErrorResponse,
14+
createMcpSuccessResponse,
15+
mcpOrchestrationStatus,
16+
} from '@/lib/mcp/utils'
1317

1418
const logger = createLogger('McpServersAPI')
1519

1620
export const dynamic = 'force-dynamic'
1721

18-
function mcpOrchestrationStatus(errorCode: string | undefined): number {
19-
if (errorCode === 'forbidden') return 403
20-
if (errorCode === 'bad_gateway') return 502
21-
if (errorCode === 'not_found') return 404
22-
return 500
23-
}
24-
2522
/**
2623
* GET - List all registered MCP servers for the workspace
2724
*/

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ export const POST = withRouteHandler(
4040

4141
logger.info(`[${requestId}] Restored table ${tableId}`)
4242

43-
return NextResponse.json({ success: true })
43+
return NextResponse.json({
44+
success: true,
45+
data: { table: result.table },
46+
})
4447
} catch (error) {
4548
logger.error(`[${requestId}] Error restoring table ${tableId}`, error)
4649
return NextResponse.json(

apps/sim/app/api/table/route.ts

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -182,33 +182,34 @@ export const GET = withRouteHandler(async (request: NextRequest) => {
182182

183183
logger.info(`[${requestId}] Listed ${tables.length} tables in workspace ${params.workspaceId}`)
184184

185+
const responseTables = tables.map((t) => {
186+
const schemaData = t.schema as TableSchema
187+
return {
188+
id: t.id,
189+
name: t.name,
190+
description: t.description,
191+
schema: {
192+
columns: schemaData.columns.map(normalizeColumn),
193+
},
194+
rowCount: t.rowCount,
195+
maxRows: t.maxRows,
196+
workspaceId: t.workspaceId,
197+
createdBy: t.createdBy,
198+
createdAt: t.createdAt instanceof Date ? t.createdAt.toISOString() : String(t.createdAt),
199+
updatedAt: t.updatedAt instanceof Date ? t.updatedAt.toISOString() : String(t.updatedAt),
200+
archivedAt:
201+
t.archivedAt instanceof Date
202+
? t.archivedAt.toISOString()
203+
: t.archivedAt
204+
? String(t.archivedAt)
205+
: null,
206+
}
207+
})
208+
185209
return NextResponse.json({
186210
success: true,
187211
data: {
188-
tables: tables.map((t) => {
189-
const schemaData = t.schema as TableSchema
190-
return {
191-
id: t.id,
192-
name: t.name,
193-
description: t.description,
194-
schema: {
195-
columns: schemaData.columns.map(normalizeColumn),
196-
},
197-
rowCount: t.rowCount,
198-
maxRows: t.maxRows,
199-
createdBy: t.createdBy,
200-
createdAt:
201-
t.createdAt instanceof Date ? t.createdAt.toISOString() : String(t.createdAt),
202-
updatedAt:
203-
t.updatedAt instanceof Date ? t.updatedAt.toISOString() : String(t.updatedAt),
204-
archivedAt:
205-
t.archivedAt instanceof Date
206-
? t.archivedAt.toISOString()
207-
: t.archivedAt
208-
? String(t.archivedAt)
209-
: null,
210-
}
211-
}),
212+
tables: responseTables,
212213
totalCount: tables.length,
213214
},
214215
})

apps/sim/app/api/workspaces/[id]/files/download/route.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { createLogger } from '@sim/logger'
2-
import { toError } from '@sim/utils/errors'
32
import JSZip from 'jszip'
43
import { type NextRequest, NextResponse } from 'next/server'
54
import { downloadWorkspaceFileItemsContract } from '@/lib/api/contracts/workspace-file-folders'
@@ -145,7 +144,7 @@ export const GET = withRouteHandler(
145144
})
146145
} catch (error) {
147146
logger.error('Failed to download workspace file selection:', error)
148-
return NextResponse.json({ error: toError(error).message }, { status: 500 })
147+
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
149148
}
150149
}
151150
)

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

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ import {
8787
import {
8888
useDeleteWorkspaceFile,
8989
useRenameWorkspaceFile,
90-
useStorageInfo,
9190
useUploadWorkspaceFile,
9291
useWorkspaceFiles,
9392
} from '@/hooks/queries/workspace-files'
@@ -200,7 +199,6 @@ export function Files() {
200199
const updateFolder = useUpdateWorkspaceFileFolder()
201200
const moveItems = useMoveWorkspaceFileItems()
202201
const bulkArchiveItems = useBulkArchiveWorkspaceFileItems()
203-
const { data: storageInfo } = useStorageInfo()
204202

205203
const {
206204
isOpen: isContextMenuOpen,
@@ -1650,12 +1648,6 @@ export function Files() {
16501648
? 'This folder is empty'
16511649
: 'No files yet'
16521650

1653-
const storageIndicator = storageInfo ? (
1654-
<span className='text-[var(--text-tertiary)] text-caption'>
1655-
{formatFileSize(storageInfo.usedBytes)} / {formatFileSize(storageInfo.limitBytes)}
1656-
</span>
1657-
) : null
1658-
16591651
const filterContent = useMemo(() => {
16601652
const typeDisplayLabel =
16611653
typeFilter.length === 0
@@ -1890,7 +1882,6 @@ export function Files() {
18901882
filter={filterContent}
18911883
filterTags={filterTags}
18921884
headerActions={headerActionsConfig}
1893-
leadingActions={storageIndicator}
18941885
columns={COLUMNS}
18951886
rows={rows}
18961887
selectable={selectableConfig}

apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/recently-deleted.tsx

Lines changed: 75 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ interface DeletedResource {
9696
color?: string
9797
}
9898

99+
interface RestoredResourceEntry {
100+
resource: DeletedResource
101+
displayIndex: number
102+
}
103+
99104
const TABS: { id: ResourceType; label: string }[] = [
100105
{ id: 'all', label: 'All' },
101106
{ id: 'workflow', label: 'Workflows' },
@@ -157,7 +162,7 @@ export function RecentlyDeleted() {
157162
const [searchTerm, setSearchTerm] = useState('')
158163
const [activeSort, setActiveSort] = useState<SortConfig | null>(null)
159164
const [restoringIds, setRestoringIds] = useState<Set<string>>(new Set())
160-
const [restoredItems, setRestoredItems] = useState<Map<string, DeletedResource>>(new Map())
165+
const [restoredItems, setRestoredItems] = useState<Map<string, RestoredResourceEntry>>(new Map())
161166

162167
const workflowsQuery = useWorkflows(workspaceId, { scope: 'archived' })
163168
const foldersQuery = useFolders(workspaceId, { scope: 'archived' })
@@ -255,13 +260,6 @@ export function RecentlyDeleted() {
255260
})
256261
}
257262

258-
const itemIds = new Set(items.map((i) => i.id))
259-
for (const [id, resource] of restoredItems) {
260-
if (!itemIds.has(id)) {
261-
items.push(resource)
262-
}
263-
}
264-
265263
return items
266264
}, [
267265
workflowsQuery.data,
@@ -271,7 +269,6 @@ export function RecentlyDeleted() {
271269
filesQuery.data,
272270
workspaceFoldersQuery.data,
273271
workspaceId,
274-
restoredItems,
275272
])
276273

277274
const filtered = useMemo(() => {
@@ -282,7 +279,7 @@ export function RecentlyDeleted() {
282279
}
283280
const col = (activeSort ?? DEFAULT_SORT).column
284281
const dir = (activeSort ?? DEFAULT_SORT).direction
285-
return [...items].sort((a, b) => {
282+
items = [...items].sort((a, b) => {
286283
let cmp = 0
287284
switch (col) {
288285
case 'name':
@@ -297,7 +294,22 @@ export function RecentlyDeleted() {
297294
}
298295
return dir === 'asc' ? cmp : -cmp
299296
})
300-
}, [resources, activeTab, searchTerm, activeSort])
297+
298+
const itemIds = new Set(items.map((item) => item.id))
299+
for (const [id, entry] of restoredItems) {
300+
if (itemIds.has(id)) continue
301+
if (!matchesActiveTab(entry.resource, activeTab)) continue
302+
if (
303+
searchTerm.trim() &&
304+
!entry.resource.name.toLowerCase().includes(searchTerm.toLowerCase())
305+
) {
306+
continue
307+
}
308+
items.splice(Math.min(entry.displayIndex, items.length), 0, entry.resource)
309+
}
310+
311+
return items
312+
}, [resources, activeTab, searchTerm, activeSort, restoredItems])
301313

302314
const showNoResults = searchTerm.trim() && filtered.length === 0 && resources.length > 0
303315
const selectedSort = activeSort ?? DEFAULT_SORT
@@ -316,56 +328,61 @@ export function RecentlyDeleted() {
316328
current = current.parentId ? byId.get(current.parentId) : undefined
317329
}
318330
}
319-
router.push(getResourceHref(resource.workspaceId, resource.type, resource.id))
331+
const href = getResourceHref(resource.workspaceId, resource.type, resource.id)
332+
router.push(href)
320333
}
321334

322-
function handleRestore(resource: DeletedResource) {
335+
async function handleRestore(resource: DeletedResource) {
336+
const displayIndex = Math.max(
337+
0,
338+
filtered.findIndex((item) => item.id === resource.id)
339+
)
323340
setRestoringIds((prev) => new Set(prev).add(resource.id))
324341

325-
const onSettled = () => {
342+
try {
343+
switch (resource.type) {
344+
case 'workflow':
345+
await restoreWorkflow.mutateAsync({
346+
workflowId: resource.id,
347+
workspaceId: resource.workspaceId,
348+
})
349+
break
350+
case 'folder':
351+
await restoreFolder.mutateAsync({
352+
folderId: resource.id,
353+
workspaceId: resource.workspaceId,
354+
})
355+
break
356+
case 'table':
357+
await restoreTable.mutateAsync(resource.id)
358+
break
359+
case 'knowledge':
360+
await restoreKnowledgeBase.mutateAsync(resource.id)
361+
break
362+
case 'file':
363+
await restoreWorkspaceFile.mutateAsync({
364+
workspaceId: resource.workspaceId,
365+
fileId: resource.id,
366+
})
367+
break
368+
case 'workspace_folder':
369+
await restoreWorkspaceFileFolder.mutateAsync({
370+
workspaceId: resource.workspaceId,
371+
folderId: resource.id,
372+
})
373+
break
374+
}
375+
376+
setRestoredItems((prev) => new Map(prev).set(resource.id, { resource, displayIndex }))
377+
} catch {
378+
return
379+
} finally {
326380
setRestoringIds((prev) => {
327381
const next = new Set(prev)
328382
next.delete(resource.id)
329383
return next
330384
})
331385
}
332-
333-
const onSuccess = () => {
334-
setRestoredItems((prev) => new Map(prev).set(resource.id, resource))
335-
}
336-
337-
switch (resource.type) {
338-
case 'workflow':
339-
restoreWorkflow.mutate(
340-
{ workflowId: resource.id, workspaceId: resource.workspaceId },
341-
{ onSettled, onSuccess }
342-
)
343-
break
344-
case 'folder':
345-
restoreFolder.mutate(
346-
{ folderId: resource.id, workspaceId: resource.workspaceId },
347-
{ onSettled, onSuccess }
348-
)
349-
break
350-
case 'table':
351-
restoreTable.mutate(resource.id, { onSettled, onSuccess })
352-
break
353-
case 'knowledge':
354-
restoreKnowledgeBase.mutate(resource.id, { onSettled, onSuccess })
355-
break
356-
case 'file':
357-
restoreWorkspaceFile.mutate(
358-
{ workspaceId: resource.workspaceId, fileId: resource.id },
359-
{ onSettled, onSuccess }
360-
)
361-
break
362-
case 'workspace_folder':
363-
restoreWorkspaceFileFolder.mutate(
364-
{ workspaceId: resource.workspaceId, folderId: resource.id },
365-
{ onSettled, onSuccess }
366-
)
367-
break
368-
}
369386
}
370387

371388
return (
@@ -460,7 +477,11 @@ export function RecentlyDeleted() {
460477
</span>
461478
</div>
462479

463-
{isRestored ? (
480+
{isRestoring ? (
481+
<Button variant='primary' size='sm' disabled className='shrink-0'>
482+
Restoring...
483+
</Button>
484+
) : isRestored ? (
464485
<div className='flex shrink-0 items-center gap-2'>
465486
<span className='text-[var(--text-tertiary)] text-small'>Restored</span>
466487
<Button variant='primary' size='sm' onClick={() => handleView(resource)}>
@@ -471,11 +492,10 @@ export function RecentlyDeleted() {
471492
<Button
472493
variant='primary'
473494
size='sm'
474-
disabled={isRestoring}
475-
onClick={() => handleRestore(resource)}
495+
onClick={() => void handleRestore(resource)}
476496
className='shrink-0'
477497
>
478-
{isRestoring ? 'Restoring...' : 'Restore'}
498+
Restore
479499
</Button>
480500
)}
481501
</div>

0 commit comments

Comments
 (0)