mirror of
https://github.com/saltbo/zpan.git
synced 2026-08-28 15:51:29 +08:00
fix(trash): list nested trashed roots
This commit is contained in:
@@ -482,6 +482,31 @@ describe('Objects API', () => {
|
||||
expect(childBody.status).toBe('active')
|
||||
})
|
||||
|
||||
it('GET /api/objects?status=trashed returns trashed folder roots nested under active parents', async () => {
|
||||
const { app, db } = await createTestApp()
|
||||
const headers = await authedHeaders(app)
|
||||
await insertStorage(db)
|
||||
const orgId = await getOrgId(db)
|
||||
await insertFolder(db, orgId, { id: 'media', name: 'Media' })
|
||||
await insertFolder(db, orgId, { id: 'music', name: 'Music', parent: 'Media' })
|
||||
await insertFolder(db, orgId, { id: 'album', name: 'Album', parent: 'Media/Music' })
|
||||
await insertFile(db, orgId, { id: 'track', name: 'track.flac', parent: 'Media/Music/Album' })
|
||||
|
||||
const trashRes = await app.request('/api/objects/batch', {
|
||||
method: 'PATCH',
|
||||
headers: { ...headers, 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ action: 'trash', ids: ['album'] }),
|
||||
})
|
||||
expect(trashRes.status).toBe(200)
|
||||
|
||||
const res = await app.request('/api/objects?status=trashed', { headers })
|
||||
expect(res.status).toBe(200)
|
||||
const body = (await res.json()) as { items: Array<{ id: string }>; total: number }
|
||||
|
||||
expect(body.total).toBe(1)
|
||||
expect(body.items.map((item) => item.id)).toEqual(['album'])
|
||||
})
|
||||
|
||||
it('DELETE /api/trash purges all trashed items', async () => {
|
||||
const { app, db } = await createTestApp()
|
||||
const headers = await authedHeaders(app)
|
||||
|
||||
@@ -112,6 +112,16 @@ export async function listMatters(
|
||||
filters: ListFilters,
|
||||
): Promise<{ items: Matter[]; total: number; page: number; pageSize: number }> {
|
||||
const offset = (filters.page - 1) * filters.pageSize
|
||||
if (filters.status === 'trashed' && !filters.search && !filters.typeFilter) {
|
||||
const roots = await listTrashedRoots(db, orgId)
|
||||
return {
|
||||
items: roots.slice(offset, offset + filters.pageSize),
|
||||
total: roots.length,
|
||||
page: filters.page,
|
||||
pageSize: filters.pageSize,
|
||||
}
|
||||
}
|
||||
|
||||
const conditions = [eq(matters.orgId, orgId), eq(matters.status, filters.status)]
|
||||
const typeCond = filters.typeFilter ? typeFilterCondition(filters.typeFilter) : undefined
|
||||
if (filters.search) {
|
||||
@@ -689,5 +699,12 @@ export async function listTrashedRoots(db: Database, orgId: string): Promise<Mat
|
||||
.where(and(eq(matters.orgId, orgId), eq(matters.status, 'trashed')))
|
||||
|
||||
const trashedPaths = new Set(all.map((m) => buildPath(m.parent, m.name)))
|
||||
return all.filter((m) => !trashedPaths.has(m.parent))
|
||||
return all
|
||||
.filter((m) => !trashedPaths.has(m.parent))
|
||||
.sort((a, b) => {
|
||||
const aTrashedAt = a.trashedAt ?? 0
|
||||
const bTrashedAt = b.trashedAt ?? 0
|
||||
if (aTrashedAt !== bTrashedAt) return bTrashedAt - aTrashedAt
|
||||
return b.createdAt.getTime() - a.createdAt.getTime()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ export function useFileMutations(currentPath: string) {
|
||||
const queryClient = useQueryClient()
|
||||
const invalidate = () => {
|
||||
queryClient.invalidateQueries({ queryKey: ['objects', 'active', 'path', currentPath] })
|
||||
queryClient.invalidateQueries({ queryKey: ['objects', 'trashed'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['user', 'quota'] })
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user