Skip to content

Commit 483c35c

Browse files
committed
fix(resources): fix missing imports, memoization, and stale refs across resource pages
1 parent ffe6806 commit 483c35c

6 files changed

Lines changed: 119 additions & 113 deletions

File tree

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useParams, useRouter } from 'next/navigation'
66
import {
77
Button,
88
Columns2,
9+
Combobox,
910
type ComboboxOption,
1011
Download,
1112
DropdownMenu,
@@ -388,7 +389,7 @@ export function Files() {
388389
}
389390
}
390391
},
391-
[workspaceId]
392+
[workspaceId, uploadFile]
392393
)
393394

394395
const handleDownload = useCallback(async (file: WorkspaceFileRecord) => {

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/[documentId]/document.tsx

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useParams, useRouter, useSearchParams } from 'next/navigation'
77
import {
88
Badge,
99
Button,
10+
Combobox,
1011
Modal,
1112
ModalBody,
1213
ModalContent,
@@ -26,6 +27,7 @@ import type {
2627
ResourceRow,
2728
SearchConfig,
2829
SelectableConfig,
30+
SortConfig,
2931
} from '@/app/workspace/[workspaceId]/components'
3032
import { Resource, ResourceHeader } from '@/app/workspace/[workspaceId]/components'
3133
import {
@@ -157,8 +159,10 @@ export function Document({
157159
direction: 'asc' | 'desc'
158160
} | null>(null)
159161

160-
const enabledFilterParam =
161-
enabledFilter.length === 1 ? (enabledFilter[0] as 'enabled' | 'disabled') : 'all'
162+
const enabledFilterParam = useMemo(
163+
() => (enabledFilter.length === 1 ? (enabledFilter[0] as 'enabled' | 'disabled') : 'all'),
164+
[enabledFilter]
165+
)
162166

163167
const {
164168
chunks: initialChunks,
@@ -636,16 +640,18 @@ export function Document({
636640
</div>
637641
)
638642

639-
const filterTags: FilterTag[] = [
640-
...enabledFilter.map((value) => ({
641-
label: `Status: ${value === 'enabled' ? 'Enabled' : 'Disabled'}`,
642-
onRemove: () => {
643-
setEnabledFilter(enabledFilter.filter((v) => v !== value))
644-
setSelectedChunks(new Set())
645-
void goToPage(1)
646-
},
647-
})),
648-
]
643+
const filterTags: FilterTag[] = useMemo(
644+
() =>
645+
enabledFilter.map((value) => ({
646+
label: `Status: ${value === 'enabled' ? 'Enabled' : 'Disabled'}`,
647+
onRemove: () => {
648+
setEnabledFilter((prev) => prev.filter((v) => v !== value))
649+
setSelectedChunks(new Set())
650+
void goToPage(1)
651+
},
652+
})),
653+
[enabledFilter, goToPage]
654+
)
649655

650656
const handleChunkClick = useCallback((rowId: string) => {
651657
setSelectedChunkId(rowId)

apps/sim/app/workspace/[workspaceId]/knowledge/[id]/base.tsx

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -806,22 +806,25 @@ export function KnowledgeBase({
806806
: []),
807807
]
808808

809-
const sortConfig: SortConfig = {
810-
options: [
811-
{ id: 'filename', label: 'Name' },
812-
{ id: 'fileSize', label: 'Size' },
813-
{ id: 'tokenCount', label: 'Tokens' },
814-
{ id: 'chunkCount', label: 'Chunks' },
815-
{ id: 'uploadedAt', label: 'Uploaded' },
816-
{ id: 'enabled', label: 'Status' },
817-
],
818-
active: { column: sortBy, direction: sortOrder },
819-
onSort: (column, direction) => {
820-
setSortBy(column as DocumentSortField)
821-
setSortOrder(direction)
822-
setCurrentPage(1)
823-
},
824-
}
809+
const sortConfig: SortConfig = useMemo(
810+
() => ({
811+
options: [
812+
{ id: 'filename', label: 'Name' },
813+
{ id: 'fileSize', label: 'Size' },
814+
{ id: 'tokenCount', label: 'Tokens' },
815+
{ id: 'chunkCount', label: 'Chunks' },
816+
{ id: 'uploadedAt', label: 'Uploaded' },
817+
{ id: 'enabled', label: 'Status' },
818+
],
819+
active: { column: sortBy, direction: sortOrder },
820+
onSort: (column, direction) => {
821+
setSortBy(column as DocumentSortField)
822+
setSortOrder(direction)
823+
setCurrentPage(1)
824+
},
825+
}),
826+
[sortBy, sortOrder]
827+
)
825828

826829
const filterContent = (
827830
<div className='flex w-[240px] flex-col gap-3 p-3'>
@@ -897,36 +900,39 @@ export function KnowledgeBase({
897900
</>
898901
) : null
899902

900-
const filterTags: FilterTag[] = [
901-
...(enabledFilter.length > 0
902-
? [
903-
{
904-
label:
905-
enabledFilter.length === 1
906-
? `Status: ${enabledFilter[0] === 'enabled' ? 'Enabled' : 'Disabled'}`
907-
: 'Status: 2 selected',
908-
onRemove: () => {
909-
setEnabledFilter([])
910-
setCurrentPage(1)
911-
setSelectedDocuments(new Set())
912-
setIsSelectAllMode(false)
903+
const filterTags: FilterTag[] = useMemo(
904+
() => [
905+
...(enabledFilter.length > 0
906+
? [
907+
{
908+
label:
909+
enabledFilter.length === 1
910+
? `Status: ${enabledFilter[0] === 'enabled' ? 'Enabled' : 'Disabled'}`
911+
: 'Status: 2 selected',
912+
onRemove: () => {
913+
setEnabledFilter([])
914+
setCurrentPage(1)
915+
setSelectedDocuments(new Set())
916+
setIsSelectAllMode(false)
917+
},
913918
},
919+
]
920+
: []),
921+
...tagFilterEntries
922+
.filter((f) => f.tagSlot && f.value.trim())
923+
.map((f) => ({
924+
label: `${f.tagName}: ${f.value}`,
925+
onRemove: () => {
926+
const updated = tagFilterEntries.filter((_, idx) => idx !== tagFilterEntries.indexOf(f))
927+
setTagFilterEntries(updated)
928+
setCurrentPage(1)
929+
setSelectedDocuments(new Set())
930+
setIsSelectAllMode(false)
914931
},
915-
]
916-
: []),
917-
...tagFilterEntries
918-
.filter((f) => f.tagSlot && f.value.trim())
919-
.map((f) => ({
920-
label: `${f.tagName}: ${f.value}`,
921-
onRemove: () => {
922-
const updated = tagFilterEntries.filter((_, idx) => idx !== tagFilterEntries.indexOf(f))
923-
setTagFilterEntries(updated)
924-
setCurrentPage(1)
925-
setSelectedDocuments(new Set())
926-
setIsSelectAllMode(false)
927-
},
928-
})),
929-
]
932+
})),
933+
],
934+
[enabledFilter, tagFilterEntries]
935+
)
930936

931937
const selectableConfig: SelectableConfig = {
932938
selectedIds: selectedDocuments,

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import type {
3939
ResourceColumn,
4040
ResourceRow,
4141
SearchConfig,
42+
SortConfig,
4243
} from '@/app/workspace/[workspaceId]/components'
4344
import {
4445
ResourceHeader,
@@ -479,12 +480,12 @@ export default function Logs() {
479480
const handleLogContextMenu = useCallback(
480481
(e: React.MouseEvent, rowId: string) => {
481482
e.preventDefault()
482-
const log = logs.find((l) => l.id === rowId) ?? null
483+
const log = sortedLogs.find((l) => l.id === rowId) ?? null
483484
setContextMenuPosition({ x: e.clientX, y: e.clientY })
484485
setContextMenuLog(log)
485486
setContextMenuOpen(true)
486487
},
487-
[logs]
488+
[sortedLogs]
488489
)
489490

490491
const handleCopyExecutionId = useCallback(() => {
@@ -1072,7 +1073,7 @@ export default function Logs() {
10721073
label: 'Export',
10731074
icon: Download,
10741075
onClick: handleExport,
1075-
disabled: !userPermissions.canEdit || isExporting || logs.length === 0,
1076+
disabled: !userPermissions.canEdit || isExporting || sortedLogs.length === 0,
10761077
},
10771078
{
10781079
label: 'Notifications',
@@ -1105,7 +1106,7 @@ export default function Logs() {
11051106
handleExport,
11061107
userPermissions.canEdit,
11071108
isExporting,
1108-
logs.length,
1109+
sortedLogs.length,
11091110
handleOpenNotificationSettings,
11101111
]
11111112
)
@@ -1387,7 +1388,7 @@ function LogsFilterPanel({ searchQuery, onSearchQueryChange }: LogsFilterPanelPr
13871388
}, [resetFilters, onSearchQueryChange])
13881389

13891390
return (
1390-
<div className='flex flex-col gap-3 p-3'>
1391+
<div className='flex w-[240px] flex-col gap-3 p-3'>
13911392
<div className='flex flex-col gap-1.5'>
13921393
<span className='font-medium text-[var(--text-secondary)] text-caption'>Status</span>
13931394
<Combobox

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

Lines changed: 26 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,7 @@
33
import { useMemo, useState } from 'react'
44
import { Search } from 'lucide-react'
55
import { useParams, useRouter } from 'next/navigation'
6-
import {
7-
ArrowUpDown,
8-
Button,
9-
DropdownMenu,
10-
DropdownMenuContent,
11-
DropdownMenuItem,
12-
DropdownMenuTrigger,
13-
SModalTabs,
14-
SModalTabsList,
15-
SModalTabsTrigger,
16-
} from '@/components/emcn'
6+
import { Button, Combobox, SModalTabs, SModalTabsList, SModalTabsTrigger } from '@/components/emcn'
177
import { Input } from '@/components/ui'
188
import { formatDate } from '@/lib/core/utils/formatting'
199
import { RESOURCE_REGISTRY } from '@/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry'
@@ -51,6 +41,8 @@ interface SortConfig {
5141
direction: 'asc' | 'desc'
5242
}
5343

44+
const DEFAULT_SORT: SortConfig = { column: 'deleted', direction: 'desc' }
45+
5446
const SORT_OPTIONS: { column: SortColumn; direction: 'asc' | 'desc'; label: string }[] = [
5547
{ column: 'deleted', direction: 'desc', label: 'Deleted (newest first)' },
5648
{ column: 'name', direction: 'asc', label: 'Name (A–Z)' },
@@ -214,8 +206,8 @@ export function RecentlyDeleted() {
214206
const normalized = searchTerm.toLowerCase()
215207
items = items.filter((r) => r.name.toLowerCase().includes(normalized))
216208
}
217-
const col = activeSort?.column ?? 'deleted'
218-
const dir = activeSort?.direction ?? 'desc'
209+
const col = (activeSort ?? DEFAULT_SORT).column
210+
const dir = (activeSort ?? DEFAULT_SORT).direction
219211
return [...items].sort((a, b) => {
220212
let cmp = 0
221213
switch (col) {
@@ -234,6 +226,7 @@ export function RecentlyDeleted() {
234226
}, [resources, activeTab, searchTerm, activeSort])
235227

236228
const showNoResults = searchTerm.trim() && filtered.length === 0 && resources.length > 0
229+
const selectedSort = activeSort ?? DEFAULT_SORT
237230

238231
function handleRestore(resource: DeletedResource) {
239232
setRestoringIds((prev) => new Set(prev).add(resource.id))
@@ -285,43 +278,27 @@ export function RecentlyDeleted() {
285278
className='h-auto flex-1 border-0 bg-transparent p-0 font-base leading-none placeholder:text-[var(--text-tertiary)] focus-visible:ring-0 focus-visible:ring-offset-0'
286279
/>
287280
</div>
288-
<DropdownMenu>
289-
<DropdownMenuTrigger asChild>
290-
<Button
291-
variant='outline'
292-
size='sm'
293-
className='h-[30px] shrink-0 gap-1.5 px-2.5'
294-
disabled={isLoading}
295-
>
296-
<ArrowUpDown className='h-[12px] w-[12px]' />
297-
<span className='text-xs'>
298-
{SORT_OPTIONS.find(
299-
(o) =>
300-
o.column === (activeSort?.column ?? 'deleted') &&
301-
o.direction === (activeSort?.direction ?? 'desc')
302-
)?.label ?? 'Sort'}
303-
</span>
304-
</Button>
305-
</DropdownMenuTrigger>
306-
<DropdownMenuContent align='end' className='w-48'>
307-
{SORT_OPTIONS.map((option) => {
308-
const isActive =
309-
(activeSort?.column ?? 'deleted') === option.column &&
310-
(activeSort?.direction ?? 'desc') === option.direction
311-
return (
312-
<DropdownMenuItem
313-
key={`${option.column}-${option.direction}`}
314-
onClick={() =>
315-
setActiveSort({ column: option.column, direction: option.direction })
316-
}
317-
className={isActive ? 'bg-[var(--bg-selected)]' : ''}
318-
>
319-
{option.label}
320-
</DropdownMenuItem>
281+
<div className='w-[190px] shrink-0'>
282+
<Combobox
283+
size='sm'
284+
align='end'
285+
disabled={isLoading}
286+
value={`${selectedSort.column}:${selectedSort.direction}`}
287+
onChange={(value) => {
288+
const option = SORT_OPTIONS.find(
289+
(sortOption) => `${sortOption.column}:${sortOption.direction}` === value
321290
)
322-
})}
323-
</DropdownMenuContent>
324-
</DropdownMenu>
291+
if (option) {
292+
setActiveSort({ column: option.column, direction: option.direction })
293+
}
294+
}}
295+
options={SORT_OPTIONS.map((option) => ({
296+
label: option.label,
297+
value: `${option.column}:${option.direction}`,
298+
}))}
299+
className='h-[30px] rounded-lg border-[var(--border)] bg-transparent px-2.5 text-small dark:bg-[var(--surface-4)]'
300+
/>
301+
</div>
325302
</div>
326303

327304
<SModalTabs value={activeTab} onValueChange={(v) => setActiveTab(v as ResourceType)}>

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,24 @@ export function Tables() {
137137
case 'updated':
138138
cmp = new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime()
139139
break
140+
case 'owner': {
141+
const aName = members?.find((m) => m.userId === a.createdBy)?.name ?? ''
142+
const bName = members?.find((m) => m.userId === b.createdBy)?.name ?? ''
143+
cmp = aName.localeCompare(bName)
144+
break
145+
}
140146
}
141147
return dir === 'asc' ? cmp : -cmp
142148
})
143-
}, [tables, debouncedSearchTerm, rowCountFilter, ownerFilter, columnTypeFilter, activeSort])
149+
}, [
150+
tables,
151+
debouncedSearchTerm,
152+
rowCountFilter,
153+
ownerFilter,
154+
columnTypeFilter,
155+
activeSort,
156+
members,
157+
])
144158

145159
const rows: ResourceRow[] = useMemo(
146160
() =>
@@ -184,6 +198,7 @@ export function Tables() {
184198
{ id: 'columns', label: 'Columns' },
185199
{ id: 'rows', label: 'Rows' },
186200
{ id: 'created', label: 'Created' },
201+
{ id: 'owner', label: 'Owner' },
187202
{ id: 'updated', label: 'Last Updated' },
188203
],
189204
active: activeSort,
@@ -466,7 +481,7 @@ export function Tables() {
466481
}
467482
}
468483
},
469-
[workspaceId, router]
484+
[workspaceId, router, uploadCsv]
470485
)
471486

472487
const handleListUploadCsv = useCallback(() => {

0 commit comments

Comments
 (0)