updated page service & controller, recycle bin modal

This commit is contained in:
Eddy Oyieko
2024-09-20 12:07:51 +03:00
parent bda2dda12d
commit 9b04cfa0fe
6 changed files with 37 additions and 8 deletions

View File

@ -13,6 +13,7 @@ import { IMovePage, IPage } from "@/features/page/types/page.types.ts";
import { useNavigate, useParams } from "react-router-dom"; import { useNavigate, useParams } from "react-router-dom";
import { import {
useCreatePageMutation, useCreatePageMutation,
// useDeletePageMutation,
useRemovePageMutation, useRemovePageMutation,
useMovePageMutation, useMovePageMutation,
useUpdatePageMutation, useUpdatePageMutation,
@ -27,7 +28,8 @@ export function useTreeMutation<T>(spaceId: string) {
const tree = useMemo(() => new SimpleTree<SpaceTreeNode>(data), [data]); const tree = useMemo(() => new SimpleTree<SpaceTreeNode>(data), [data]);
const createPageMutation = useCreatePageMutation(); const createPageMutation = useCreatePageMutation();
const updatePageMutation = useUpdatePageMutation(); const updatePageMutation = useUpdatePageMutation();
const deletePageMutation = useRemovePageMutation(); // const deletePageMutation = useDeletePageMutation();
const removePageMutation = useRemovePageMutation();
const movePageMutation = useMovePageMutation(); const movePageMutation = useMovePageMutation();
const navigate = useNavigate(); const navigate = useNavigate();
const { spaceSlug } = useParams(); const { spaceSlug } = useParams();
@ -180,7 +182,7 @@ export function useTreeMutation<T>(spaceId: string) {
const onDelete: DeleteHandler<T> = async (args: { ids: string[] }) => { const onDelete: DeleteHandler<T> = async (args: { ids: string[] }) => {
try { try {
await deletePageMutation.mutateAsync(args.ids[0]); await removePageMutation.mutateAsync(args.ids[0]);
if (tree.find(args.ids[0])) { if (tree.find(args.ids[0])) {
tree.drop({ id: args.ids[0] }); tree.drop({ id: args.ids[0] });

View File

@ -3,6 +3,10 @@ import React, { useMemo } from "react";
import { useSpaceQuery } from "@/features/space/queries/space-query.ts"; import { useSpaceQuery } from "@/features/space/queries/space-query.ts";
import { useSpaceAbility } from "@/features/space/permissions/use-space-ability.ts"; import { useSpaceAbility } from "@/features/space/permissions/use-space-ability.ts";
import RecycledPagesList from "@/features/space/components/recycled-pages.tsx" import RecycledPagesList from "@/features/space/components/recycled-pages.tsx"
import {
SpaceCaslAction,
SpaceCaslSubject,
} from "@/features/space/permissions/permissions.type.ts";
interface RecycleBinModalProps { interface RecycleBinModalProps {
spaceId: string; spaceId: string;
@ -40,7 +44,13 @@ export default function RecycleBinModal({
<Modal.Body> <Modal.Body>
<div style={{ height: rem("600px") }}> <div style={{ height: rem("600px") }}>
<ScrollArea h="600" w="100%" scrollbarSize={5}> <ScrollArea h="600" w="100%" scrollbarSize={5}>
<RecycledPagesList spaceId={space.id} /> <RecycledPagesList
spaceId={space?.id}
readOnly={spaceAbility.cannot(
SpaceCaslAction.Manage,
SpaceCaslSubject.Page
)}
/>
</ScrollArea> </ScrollArea>
</div> </div>
</Modal.Body> </Modal.Body>

View File

@ -10,6 +10,7 @@ interface RecycledPagesProps {
export default function RecycledPagesList({ export default function RecycledPagesList({
spaceId, spaceId,
readOnly,
}: RecycledPagesProps) { }: RecycledPagesProps) {
const { data, isLoading } = useDeletedPagesQuery(spaceId); const { data, isLoading } = useDeletedPagesQuery(spaceId);
const restorePageMutation = useRestorePageMutation(); const restorePageMutation = useRestorePageMutation();
@ -65,13 +66,13 @@ export default function RecycledPagesList({
<Table.Td> <Table.Td>
<div> <div>
<Text fz="sm" fw={500}> <Text fz="sm" fw={500}>
{page?.title} {page?.title || "Untitled"}
</Text> </Text>
</div> </div>
</Table.Td> </Table.Td>
<Table.Td> <Table.Td>
{( {!readOnly && (
<Menu> <Menu>
<Menu.Target> <Menu.Target>
<ActionIcon variant="subtle" c="gray"> <ActionIcon variant="subtle" c="gray">
@ -88,7 +89,7 @@ export default function RecycledPagesList({
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item
onClick={() => onClick={() =>
openRemovePageModal openRemovePageModal(page.id)
}> }>
Delete Page permanently Delete Page permanently
</Menu.Item> </Menu.Item>

View File

@ -12,6 +12,7 @@ import { PageService } from './services/page.service';
import { CreatePageDto } from './dto/create-page.dto'; import { CreatePageDto } from './dto/create-page.dto';
import { UpdatePageDto } from './dto/update-page.dto'; import { UpdatePageDto } from './dto/update-page.dto';
import { MovePageDto } from './dto/move-page.dto'; import { MovePageDto } from './dto/move-page.dto';
// import { RestorePageDto } from './dto/restore-page.dto';
import { PageHistoryIdDto, PageIdDto, PageInfoDto } from './dto/page.dto'; import { PageHistoryIdDto, PageIdDto, PageInfoDto } from './dto/page.dto';
import { PageHistoryService } from './services/page-history.service'; import { PageHistoryService } from './services/page-history.service';
import { AuthUser } from '../../common/decorators/auth-user.decorator'; import { AuthUser } from '../../common/decorators/auth-user.decorator';
@ -132,8 +133,19 @@ export class PageController {
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)
@Post('restore') @Post('restore')
async restore(@Body() pageIdDto: PageIdDto) { async restore(@Body() pageIdDto: PageIdDto, @AuthUser() user: User) {
await this.pageService.restore(pageIdDto.pageId); const page = await this.pageRepo.findById(pageIdDto.pageId);
if (!page) {
throw new NotFoundException('Page not found');
}
const ability = await this.spaceAbility.createForUser(user, page.spaceId);
if (ability.cannot(SpaceCaslAction.Manage, SpaceCaslSubject.Page)) {
throw new ForbiddenException();
}
await this.pageService.restore(pageIdDto.pageId);
} }
@HttpCode(HttpStatus.OK) @HttpCode(HttpStatus.OK)

View File

@ -162,9 +162,11 @@ export class PageService {
'parentPageId', 'parentPageId',
'spaceId', 'spaceId',
'creatorId', 'creatorId',
'deletedAt',
]) ])
.select((eb) => this.withHasChildren(eb)) .select((eb) => this.withHasChildren(eb))
.orderBy('position', 'asc') .orderBy('position', 'asc')
.where('deletedAt', 'is', null)
.where('spaceId', '=', spaceId); .where('spaceId', '=', spaceId);
if (pageId) { if (pageId) {

View File

@ -148,6 +148,7 @@ export class PageRepo {
.select(this.baseFields) .select(this.baseFields)
.select((eb) => this.withSpace(eb)) .select((eb) => this.withSpace(eb))
.where('spaceId', '=', spaceId) .where('spaceId', '=', spaceId)
.where('deletedAt', 'is not', null)
.orderBy('updatedAt', 'desc'); .orderBy('updatedAt', 'desc');
const result = executeWithPagination(query, { const result = executeWithPagination(query, {
@ -166,6 +167,7 @@ export class PageRepo {
.select(this.baseFields) .select(this.baseFields)
.select((eb) => this.withSpace(eb)) .select((eb) => this.withSpace(eb))
.where('spaceId', 'in', userSpaceIds) .where('spaceId', 'in', userSpaceIds)
.where('deletedAt', 'is not', null)
.orderBy('updatedAt', 'desc'); .orderBy('updatedAt', 'desc');
const result = executeWithPagination(query, { const result = executeWithPagination(query, {