Skip to content

Commit 94289e9

Browse files
committed
fix(recently-deleted): cast chat ids in the trash union, keep loaded pages on errors
1 parent 4a859dd commit 94289e9

10 files changed

Lines changed: 61 additions & 24 deletions

File tree

‎apps/sim/app/api/workspaces/[id]/recently-deleted/route.ts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ export const GET = defineInternalJsonRoute({
4242
),
4343
}),
4444
useCase: listRecentlyDeleted,
45-
present: ({ items, nextCursorKeys }, { params, query }) => ({
45+
present: ({ items, nextCursorKeys }, { input }) => ({
4646
items,
4747
nextCursor: writeSortedCursor(
4848
nextCursorKeys,
49-
query.sortBy,
50-
query.sortOrder,
51-
cursorScope(params.id, query.type, query.search)
49+
input.sortBy,
50+
input.sortOrder,
51+
cursorScope(input.workspaceId, input.filter, input.search)
5252
),
5353
}),
5454
})

‎apps/sim/app/workspace/[workspaceId]/components/resource/resource.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ const ResourceTable = memo(function ResourceTable({
288288
emptyState,
289289
}: ResourceTableProps) {
290290
const scrollRef = useRef<HTMLDivElement>(null)
291-
const loadMoreRef = useLoadMoreSentinel(onLoadMore, Boolean(hasMore))
291+
const loadMoreRef = useLoadMoreSentinel({ onLoadMore, enabled: Boolean(hasMore) })
292292

293293
const showEmptyState = rows.length === 0 && Boolean(emptyState)
294294

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

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import { useMemo, useState } from 'react'
44
import { Chip, ChipInput, ChipModalTabs } from '@sim/emcn'
55
import { Search } from '@sim/emcn/icons'
6-
import { toError } from '@sim/utils/errors'
76
import { formatDate } from '@sim/utils/formatting'
87
import { useParams, useRouter } from 'next/navigation'
98
import { useQueryStates } from 'nuqs'
@@ -27,7 +26,10 @@ import {
2726
recentlyDeletedSortParams,
2827
recentlyDeletedUrlKeys,
2928
} from '@/app/workspace/[workspaceId]/settings/components/recently-deleted/search-params'
30-
import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
29+
import {
30+
SettingsEmptyState,
31+
SettingsQueryErrorState,
32+
} from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state'
3133
import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel'
3234
import {
3335
RESOURCE_LIST_STACK,
@@ -232,9 +234,13 @@ export function RecentlyDeleted() {
232234
const restoreWorkspaceFileFolder = useRestoreWorkspaceFileFolder()
233235
const restoreChat = useRestoreMothershipChat(workspaceId)
234236

235-
const { hasNextPage, isFetchingNextPage, fetchNextPage, isLoading, error } = deletedQuery
237+
const { hasNextPage, isFetchingNextPage, isFetchNextPageError, fetchNextPage, isLoading, error } =
238+
deletedQuery
236239

237-
const loadMoreRef = useLoadMoreSentinel(fetchNextPage, hasNextPage && !isFetchingNextPage)
240+
const loadMoreRef = useLoadMoreSentinel({
241+
onLoadMore: fetchNextPage,
242+
enabled: hasNextPage && !isFetchingNextPage && !isFetchNextPageError,
243+
})
238244

239245
const filtered = useMemo(() => {
240246
const items: DeletedResource[] = (deletedQuery.data?.pages ?? []).flatMap((page) =>
@@ -374,10 +380,13 @@ export function RecentlyDeleted() {
374380
onChange={(v) => setRecentlyDeletedFilters({ tab: v as RecentlyDeletedFilter })}
375381
/>
376382

377-
{error ? (
378-
<SettingsEmptyState>
379-
{toError(error).message || 'Failed to load deleted items'}
380-
</SettingsEmptyState>
383+
{error && !deletedQuery.data ? (
384+
<SettingsQueryErrorState
385+
error={error}
386+
fallback='Failed to load deleted items'
387+
isRetrying={deletedQuery.isFetching}
388+
onRetry={() => void deletedQuery.refetch()}
389+
/>
381390
) : isLoading && filtered.length === 0 ? null : filtered.length === 0 ? (
382391
showNoResults ? (
383392
<SettingsEmptyState variant='inline'>
@@ -435,7 +444,17 @@ export function RecentlyDeleted() {
435444
/>
436445
)
437446
})}
438-
<div ref={loadMoreRef} aria-hidden />
447+
{isFetchNextPageError ? (
448+
<SettingsQueryErrorState
449+
error={error}
450+
fallback='Failed to load more deleted items'
451+
isRetrying={isFetchingNextPage}
452+
onRetry={() => void fetchNextPage()}
453+
variant='inline'
454+
/>
455+
) : (
456+
<div ref={loadMoreRef} aria-hidden />
457+
)}
439458
</div>
440459
)}
441460
</SettingsPanel>

‎apps/sim/hooks/queries/recently-deleted.ts‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { keepPreviousData, useInfiniteQuery } from '@tanstack/react-query'
1+
import { useInfiniteQuery } from '@tanstack/react-query'
22
import { requestJson } from '@/lib/api/client/request'
33
import {
44
listRecentlyDeletedContract,
@@ -10,7 +10,7 @@ import { recentlyDeletedKeys } from '@/hooks/queries/utils/recently-deleted-keys
1010
import { shouldRetrySettingsRead } from '@/hooks/queries/utils/settings-read-retry'
1111

1212
/** Always refetched on open, so a resource deleted anywhere else shows up here. */
13-
export const RECENTLY_DELETED_STALE_TIME = 0
13+
const RECENTLY_DELETED_STALE_TIME = 0
1414

1515
interface RecentlyDeletedListParams {
1616
workspaceId: string
@@ -41,7 +41,12 @@ export function useRecentlyDeletedItems({
4141
getNextPageParam: (page) => page.nextCursor ?? undefined,
4242
enabled: Boolean(workspaceId),
4343
staleTime: RECENTLY_DELETED_STALE_TIME,
44-
placeholderData: keepPreviousData,
44+
placeholderData: (previous, previousQuery) =>
45+
recentlyDeletedKeys
46+
.workspaceLists(workspaceId)
47+
.every((part, index) => previousQuery?.queryKey[index] === part)
48+
? previous
49+
: undefined,
4550
retry: shouldRetrySettingsRead,
4651
})
4752
}

‎apps/sim/hooks/queries/utils/recently-deleted-keys.ts‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@ import type { ListSortOrder } from '@/lib/api/list-query'
1212
export const recentlyDeletedKeys = {
1313
all: ['recentlyDeleted'] as const,
1414
lists: () => [...recentlyDeletedKeys.all, 'list'] as const,
15+
/** Every list in one workspace — the scope a previous page may be carried within. */
16+
workspaceLists: (workspaceId: string) => [...recentlyDeletedKeys.lists(), workspaceId] as const,
1517
list: (
1618
workspaceId: string,
1719
filter: RecentlyDeletedFilter,
1820
search: string | undefined,
1921
sortBy: RecentlyDeletedSortColumn,
2022
sortOrder: ListSortOrder
2123
) =>
22-
[...recentlyDeletedKeys.lists(), workspaceId, filter, search ?? '', sortBy, sortOrder] as const,
24+
[
25+
...recentlyDeletedKeys.workspaceLists(workspaceId),
26+
filter,
27+
search ?? '',
28+
sortBy,
29+
sortOrder,
30+
] as const,
2331
}

‎apps/sim/hooks/use-load-more-sentinel.ts‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@
22

33
import { useCallback } from 'react'
44

5+
interface UseLoadMoreSentinelOptions {
6+
/** Loads the next page; absent means the list has no further pages to request. */
7+
onLoadMore: (() => void) | undefined
8+
/** Whether reaching the sentinel should load more right now. */
9+
enabled: boolean
10+
}
11+
512
/**
613
* A callback ref for the element at the end of a paged list: `onLoadMore` runs when it scrolls
714
* within 200px of view, while `enabled`. Pass `enabled: false` during a fetch, so the
815
* observer is rebuilt when the fetch ends and fires again if the sentinel is still in view.
916
*/
10-
export function useLoadMoreSentinel(onLoadMore: (() => void) | undefined, enabled: boolean) {
17+
export function useLoadMoreSentinel({ onLoadMore, enabled }: UseLoadMoreSentinelOptions) {
1118
return useCallback(
1219
(sentinel: HTMLDivElement | null) => {
1320
if (!sentinel || !onLoadMore || !enabled) return

‎apps/sim/lib/api/contracts/recently-deleted.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const RECENTLY_DELETED_FILTERS = [
3232

3333
export const RECENTLY_DELETED_SORT_COLUMNS = ['deleted', 'name', 'type'] as const
3434

35-
export const RECENTLY_DELETED_PAGE_SIZE = 50
35+
const RECENTLY_DELETED_PAGE_SIZE = 50
3636

3737
const recentlyDeletedItemSchema = z.object({
3838
id: z.string(),

‎apps/sim/lib/mothership/request/go/file-preview-adapter.test.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ describe('processFilePreviewStreamEvent — preview target resolution', () => {
307307

308308
beforeEach(() => {
309309
executeCopilotFileUseCaseMock.mockResolvedValue({
310-
files: [{ id: 'file-9', name: 'notes.md', folderPath: null }],
310+
files: new Map([['files/notes.md', { id: 'file-9', name: 'notes.md', folderPath: null }]]),
311311
})
312312
})
313313

‎apps/sim/lib/workspaces/recently-deleted.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ function deletedSources(options: ListRecentlyDeletedOptions): DeletedSource[] {
161161
'chat',
162162
sql`${copilotChats}`,
163163
{
164-
id: sql`${copilotChats.id}`,
164+
id: sql`${copilotChats.id}::text`,
165165
name: sql`coalesce(${copilotChats.title}, 'New chat')`,
166166
deletedAt: sql`${copilotChats.deletedAt}`,
167167
},

‎scripts/check-unused-exports.baseline.json‎

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,6 @@
572572
"apps/sim/app/workspace/[workspaceId]/settings/components/mothership/search-params.ts#MOTHERSHIP_ENVIRONMENTS",
573573
"apps/sim/app/workspace/[workspaceId]/settings/components/mothership/search-params.ts#MOTHERSHIP_TABS",
574574
"apps/sim/app/workspace/[workspaceId]/settings/components/mothership/search-params.ts#MothershipEnvironmentParam",
575-
"apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/search-params.ts#RECENTLY_DELETED_SORT_COLUMNS",
576-
"apps/sim/app/workspace/[workspaceId]/settings/components/recently-deleted/search-params.ts#RECENTLY_DELETED_TABS",
577575
"apps/sim/app/workspace/[workspaceId]/settings/components/settings-header/settings-header.tsx#SettingsBackAction",
578576
"apps/sim/app/workspace/[workspaceId]/settings/components/settings-header/settings-header.tsx#SettingsHeaderConfig",
579577
"apps/sim/app/workspace/[workspaceId]/settings/components/settings-header/settings-header.tsx#SettingsHeaderSearch",

0 commit comments

Comments
 (0)