Skip to content

Commit 12c2993

Browse files
committed
refactor: update trash service and UI components
1 parent cc0c5ab commit 12c2993

File tree

4 files changed

+75
-107
lines changed

4 files changed

+75
-107
lines changed

apps/nestjs-backend/src/features/trash/trash.service.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,21 +152,24 @@ export class TrashService {
152152

153153
private async getBaseTrash(spaceId?: string) {
154154
const { bases } = await this.getAuthorizedSpacesAndBases();
155-
const baseIds = bases.map((base) => base.id);
156-
const spaceIds = spaceId ? [spaceId] : bases.map((base) => base.spaceId);
155+
const authorizedBaseIds = bases.map((base) => base.id);
156+
const authorizedBaseSpaceIds = bases.map((base) => base.spaceId);
157157
const baseIdMap = keyBy(bases, 'id');
158158

159159
const trashedSpaces = await this.prismaService.trash.findMany({
160160
where: {
161161
resourceType: ResourceType.Space,
162-
resourceId: { in: spaceIds },
162+
resourceId: { in: authorizedBaseSpaceIds },
163163
},
164164
select: { resourceId: true },
165165
});
166166
const list = await this.prismaService.trash.findMany({
167167
where: {
168-
parentId: { notIn: trashedSpaces.map((space) => space.resourceId) },
169-
resourceId: { in: baseIds },
168+
parentId: {
169+
notIn: trashedSpaces.map((space) => space.resourceId),
170+
in: spaceId ? [spaceId] : undefined,
171+
},
172+
resourceId: { in: authorizedBaseIds },
170173
resourceType: ResourceType.Base,
171174
},
172175
});

apps/nextjs-app/src/features/app/blocks/trash/SpaceInnerTrashPage.tsx

Lines changed: 37 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useInfiniteQuery, useMutation, useQueryClient } from '@tanstack/react-query';
22
import type { ColumnDef } from '@tanstack/react-table';
3-
import { MoreHorizontal, RefreshCcw, Trash2 } from '@teable/icons';
3+
import { Database, RefreshCcw, Trash2 } from '@teable/icons';
44
import type { ITrashItemVo, ITrashVo } from '@teable/openapi';
55
import {
66
getTrash,
@@ -13,13 +13,7 @@ import { InfiniteTable } from '@teable/sdk/components';
1313
import { ReactQueryKeys } from '@teable/sdk/config';
1414
import { useIsHydrated } from '@teable/sdk/hooks';
1515
import { ConfirmDialog } from '@teable/ui-lib/base';
16-
import {
17-
Button,
18-
DropdownMenu,
19-
DropdownMenuContent,
20-
DropdownMenuItem,
21-
DropdownMenuTrigger,
22-
} from '@teable/ui-lib/shadcn';
16+
import { Button } from '@teable/ui-lib/shadcn';
2317
import { toast } from '@teable/ui-lib/shadcn/ui/sonner';
2418
import dayjs from 'dayjs';
2519
import { useParams } from 'next/navigation';
@@ -58,7 +52,7 @@ export const SpaceInnerTrashPage = () => {
5852
};
5953

6054
const { data, isFetching, isLoading, fetchNextPage } = useInfiniteQuery({
61-
queryKey: ReactQueryKeys.getSpaceTrash(resourceType),
55+
queryKey: ReactQueryKeys.getSpaceTrash(resourceType, spaceId),
6256
queryFn,
6357
refetchOnMount: 'always',
6458
refetchOnWindowFocus: false,
@@ -69,15 +63,15 @@ export const SpaceInnerTrashPage = () => {
6963
mutationFn: (props: { trashId: string }) => restoreTrash(props.trashId),
7064
onSuccess: () => {
7165
queryClient.invalidateQueries(ReactQueryKeys.spaceList());
72-
queryClient.invalidateQueries(ReactQueryKeys.getSpaceTrash(resourceType));
66+
queryClient.invalidateQueries(ReactQueryKeys.getSpaceTrash(resourceType, spaceId));
7367
toast.success(t('actions.restoreSucceed'));
7468
},
7569
});
7670

7771
const { mutateAsync: mutatePermanentDeleteBase } = useMutation({
7872
mutationFn: (props: { baseId: string }) => permanentDeleteBase(props.baseId),
7973
onSuccess: () => {
80-
queryClient.invalidateQueries(ReactQueryKeys.getSpaceTrash(resourceType));
74+
queryClient.invalidateQueries(ReactQueryKeys.getSpaceTrash(resourceType, spaceId));
8175
toast.success(t('actions.deleteSucceed'));
8276
},
8377
});
@@ -99,36 +93,13 @@ export const SpaceInnerTrashPage = () => {
9993
const resourceInfo = resourceMap[resourceId];
10094

10195
if (!resourceInfo) return null;
102-
10396
const { name } = resourceInfo;
104-
105-
if ('spaceId' in resourceInfo) {
106-
const spaceId = resourceInfo.spaceId;
107-
const spaceInfo = resourceMap[spaceId];
108-
109-
return (
110-
<div className="flex items-center space-x-2 pr-2 text-sm">
111-
<span>{name}</span>
112-
<Button
113-
className="text-xs"
114-
variant="outline"
115-
size="xs"
116-
onClick={() => {
117-
router.push({
118-
pathname: '/space/[spaceId]',
119-
query: { spaceId },
120-
});
121-
}}
122-
>
123-
<span className="max-w-40 truncate text-xs">
124-
{t('trash.fromSpace', { name: spaceInfo.name })}
125-
</span>
126-
</Button>
127-
</div>
128-
);
129-
}
130-
131-
return <div className="text-wrap pr-2 text-sm">{name}</div>;
97+
return (
98+
<div className="flex min-w-0 items-center gap-2 pl-2">
99+
<Database className="size-6 rounded-md border p-1" />
100+
<span className="truncate text-sm ">{name}</span>
101+
</div>
102+
);
132103
},
133104
},
134105
{
@@ -172,32 +143,32 @@ export const SpaceInnerTrashPage = () => {
172143
if (!resourceInfo) return null;
173144

174145
return (
175-
<DropdownMenu>
176-
<DropdownMenuTrigger asChild>
177-
<Button aria-haspopup="true" size="icon" variant="ghost" className="size-8">
178-
<MoreHorizontal className="size-4" />
179-
</Button>
180-
</DropdownMenuTrigger>
181-
<DropdownMenuContent align="end">
182-
<DropdownMenuItem className="gap-x-2" onClick={() => mutateRestore({ trashId })}>
183-
<RefreshCcw className="size-4" />
184-
{t('actions.restore')}
185-
</DropdownMenuItem>
186-
<DropdownMenuItem
187-
className="gap-x-2 text-destructive focus:text-destructive"
188-
onClick={() => {
189-
setConfirmVisible(true);
190-
setDeletingResource({
191-
resourceId,
192-
name: resourceInfo.name,
193-
});
194-
}}
195-
>
196-
<Trash2 className="size-4" />
197-
{t('actions.permanentDelete')}
198-
</DropdownMenuItem>
199-
</DropdownMenuContent>
200-
</DropdownMenu>
146+
<div className="flex items-center gap-1">
147+
<Button
148+
size="xs"
149+
variant="ghost"
150+
className="p-1"
151+
title={t('actions.restore')}
152+
onClick={() => mutateRestore({ trashId })}
153+
>
154+
<RefreshCcw className="size-4" />
155+
</Button>
156+
<Button
157+
size="xs"
158+
variant="ghost"
159+
className="p-1"
160+
title={t('actions.permanentDelete')}
161+
onClick={() => {
162+
setConfirmVisible(true);
163+
setDeletingResource({
164+
resourceId,
165+
name: resourceInfo.name,
166+
});
167+
}}
168+
>
169+
<Trash2 className="size-4" />
170+
</Button>
171+
</div>
201172
);
202173
},
203174
},

apps/nextjs-app/src/features/app/blocks/trash/SpaceTrashPage.tsx

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import type { QueryFunctionContext } from '@tanstack/react-query';
21
import { useInfiniteQuery, useMutation, useQueryClient } from '@tanstack/react-query';
32
import type { ColumnDef } from '@tanstack/react-table';
4-
import { MoreHorizontal, RefreshCcw, Trash2 } from '@teable/icons';
3+
import { RefreshCcw, Trash2 } from '@teable/icons';
54
import type { ITrashItemVo, ITrashVo } from '@teable/openapi';
65
import {
76
getTrash,
@@ -14,13 +13,7 @@ import { InfiniteTable } from '@teable/sdk/components';
1413
import { ReactQueryKeys } from '@teable/sdk/config';
1514
import { useIsHydrated } from '@teable/sdk/hooks';
1615
import { ConfirmDialog } from '@teable/ui-lib/base';
17-
import {
18-
Button,
19-
DropdownMenu,
20-
DropdownMenuContent,
21-
DropdownMenuItem,
22-
DropdownMenuTrigger,
23-
} from '@teable/ui-lib/shadcn';
16+
import { Button } from '@teable/ui-lib/shadcn';
2417
import { toast } from '@teable/ui-lib/shadcn/ui/sonner';
2518
import dayjs from 'dayjs';
2619
import { useTranslation } from 'next-i18next';
@@ -149,32 +142,32 @@ export const SpaceTrashPage = () => {
149142
if (!resourceInfo) return null;
150143

151144
return (
152-
<DropdownMenu>
153-
<DropdownMenuTrigger asChild>
154-
<Button aria-haspopup="true" size="icon" variant="ghost" className="size-8">
155-
<MoreHorizontal className="size-4" />
156-
</Button>
157-
</DropdownMenuTrigger>
158-
<DropdownMenuContent align="end">
159-
<DropdownMenuItem className="gap-x-2" onClick={() => mutateRestore({ trashId })}>
160-
<RefreshCcw className="size-4" />
161-
{t('actions.restore')}
162-
</DropdownMenuItem>
163-
<DropdownMenuItem
164-
className="gap-x-2 text-destructive focus:text-destructive"
165-
onClick={() => {
166-
setConfirmVisible(true);
167-
setDeletingResource({
168-
resourceId,
169-
name: resourceInfo.name,
170-
});
171-
}}
172-
>
173-
<Trash2 className="size-4" />
174-
{t('actions.permanentDelete')}
175-
</DropdownMenuItem>
176-
</DropdownMenuContent>
177-
</DropdownMenu>
145+
<div className="flex items-center gap-1">
146+
<Button
147+
size="xs"
148+
variant="ghost"
149+
className="p-1"
150+
title={t('actions.restore')}
151+
onClick={() => mutateRestore({ trashId })}
152+
>
153+
<RefreshCcw className="size-4" />
154+
</Button>
155+
<Button
156+
size="xs"
157+
variant="ghost"
158+
className="p-1"
159+
title={t('actions.permanentDelete')}
160+
onClick={() => {
161+
setConfirmVisible(true);
162+
setDeletingResource({
163+
resourceId,
164+
name: resourceInfo.name,
165+
});
166+
}}
167+
>
168+
<Trash2 className="size-4" />
169+
</Button>
170+
</div>
178171
);
179172
},
180173
},

packages/sdk/src/config/react-query-keys.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,8 @@ export const ReactQueryKeys = {
174174

175175
getSharedBase: () => ['shared-base-list'] as const,
176176

177-
getSpaceTrash: (resourceType: ResourceType) => ['space-trash', resourceType] as const,
177+
getSpaceTrash: (resourceType: ResourceType, spaceId?: string) =>
178+
['space-trash', resourceType, spaceId] as const,
178179

179180
getTrashItems: (resourceId: string) => ['trash-items', resourceId] as const,
180181

0 commit comments

Comments
 (0)