Added Pagination to Audit Log Page

This commit is contained in:
Ahmad 2024-11-01 22:07:52 -04:00
parent 10c54df886
commit c9313ff5f0
No known key found for this signature in database
GPG key ID: 8FD8A93530D182BF
4 changed files with 198 additions and 44 deletions

View file

@ -19,7 +19,7 @@ Currently, there is no documentation or wiki available but there will be one add
This will be published on the site some time soon but for now, the roadmap will be listed here.
- [ ] Finish adding started at date feature
- [ ] Pagination for Audit Logs page
- [x] Pagination for Audit Logs page
- [ ] Board sorting options (Boards Page)
- [ ] Add real-time collaboration
- [ ] Add end-to-end Database encryption (for customer data such as card titles and descriptions, and subscription information)

View file

@ -1,26 +1,28 @@
import { auth } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';
'use client';
import { db } from '@/lib/db';
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@/components/ui/pagination';
import { ActivityItem } from '@/components/activity-item';
import { Skeleton } from '@/components/ui/skeleton';
export const ActivityList = async () => {
const { orgId } = await auth();
if (!orgId) redirect('/select-org');
const auditLogs = await db.auditLog.findMany({
where: {
orgId,
},
orderBy: {
createdAt: 'desc',
},
cacheStrategy: { ttl: 30, swr: 60 },
});
import { AuditLog } from '@prisma/client';
export const ActivityList = ({
totalPages,
currentPage,
auditLogs,
}: {
totalPages: number;
currentPage: number;
auditLogs: AuditLog[];
}) => {
return (
<div>
<ol className='mt-4 space-y-4'>
<p className='hidden text-center text-xs text-muted-foreground last:block'>
No activity found inside this organization
@ -29,17 +31,114 @@ export const ActivityList = async () => {
<ActivityItem key={log.id} data={log} />
))}
</ol>
<ActivityListPagination
totalPages={totalPages}
currentPage={currentPage}
/>
</div>
);
};
ActivityList.Skeleton = function ActivityListSkeleton() {
const ActivityListPagination = ({
totalPages,
currentPage,
}: {
totalPages: number;
currentPage: number;
}) => {
const renderPageNumbers = () => {
const pageNumbers = [];
const maxVisiblePages = 5;
if (totalPages <= maxVisiblePages) {
for (let i = 1; i <= totalPages; i++) {
pageNumbers.push(
<PaginationItem key={i}>
<PaginationLink
href={`activity?page=${i}`}
isActive={currentPage === i}
>
{i}
</PaginationLink>
</PaginationItem>
);
}
} else {
// Always show first page
pageNumbers.push(
<PaginationItem key={1}>
<PaginationLink href='activity?page=1' isActive={currentPage === 1}>
1
</PaginationLink>
</PaginationItem>
);
// Show ellipsis if current page is more than 3
if (currentPage > 3) {
pageNumbers.push(
<PaginationItem key='ellipsis-start'>
<PaginationEllipsis />
</PaginationItem>
);
}
// Show current page and surrounding pages
const startPage = Math.max(2, currentPage - 1);
const endPage = Math.min(totalPages - 1, currentPage + 1);
for (let i = startPage; i <= endPage; i++) {
pageNumbers.push(
<PaginationItem key={i}>
<PaginationLink
href={`activity?page=${i}`}
isActive={currentPage === i}
>
{i}
</PaginationLink>
</PaginationItem>
);
}
// Show ellipsis if current page is less than totalPages - 2
if (currentPage < totalPages - 2) {
pageNumbers.push(
<PaginationItem key='ellipsis-end'>
<PaginationEllipsis />
</PaginationItem>
);
}
// Always show last page
pageNumbers.push(
<PaginationItem key={totalPages}>
<PaginationLink
href={`activity?page=${totalPages}`}
isActive={currentPage === totalPages}
>
{totalPages}
</PaginationLink>
</PaginationItem>
);
}
return pageNumbers;
};
return (
<ol className='mt-4 space-y-4'>
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[50%]' />
<Skeleton className='h-14 w-[70%]' />
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[75%]' />
</ol>
<Pagination>
<PaginationContent>
{currentPage > 1 && (
<PaginationItem>
<PaginationPrevious href={`activity?page=${currentPage - 1}`} />
</PaginationItem>
)}
{renderPageNumbers()}
{currentPage < totalPages && (
<PaginationItem>
<PaginationNext href={`activity?page=${currentPage + 1}`} />
</PaginationItem>
)}
</PaginationContent>
</Pagination>
);
};

View file

@ -1,23 +1,77 @@
import { auth } from '@clerk/nextjs/server';
import { redirect } from 'next/navigation';
import { Suspense } from 'react';
import { Separator } from '@/components/ui/separator';
import { Info } from '../_components/info';
import { ActivityList } from './_components/activity-list';
import { checkSubscription } from '@/lib/subscription';
const ActivityPage = async () => {
import { Separator } from '@/components/ui/separator';
import { checkSubscription } from '@/lib/subscription';
import { db } from '@/lib/db';
import { Skeleton } from '@/components/ui/skeleton';
const ActivityPage = async ({
searchParams,
}: {
searchParams: { [key: string]: string | undefined };
}) => {
const isPro = await checkSubscription();
const { orgId } = await auth();
const params = await searchParams;
const currentPage = Number(params.page);
const limit = 10;
if (!orgId) redirect('/select-org');
if (!currentPage || currentPage < 1) redirect('activity?page=1');
const skip = (currentPage - 1) * limit;
const auditLogs = await db.auditLog.findMany({
where: {
orgId,
},
orderBy: {
createdAt: 'desc',
},
skip,
take: limit,
cacheStrategy: { ttl: 30, swr: 60 },
});
const totalCount = await db.auditLog.count({
where: {
orgId,
},
cacheStrategy: { ttl: 30, swr: 60 },
});
const totalPages = Math.ceil(totalCount / limit);
return (
<div className='w-full'>
<Info isPro={isPro} />
<Separator className='my-2' />
<Suspense fallback={<ActivityList.Skeleton />}>
<ActivityList />
<Suspense fallback={<ActivityListSkeleton />}>
<ActivityList
totalPages={totalPages}
currentPage={currentPage}
auditLogs={auditLogs}
/>
</Suspense>
</div>
);
};
export default ActivityPage;
const ActivityListSkeleton = () => {
return (
<ol className='mt-4 space-y-4'>
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[50%]' />
<Skeleton className='h-14 w-[70%]' />
<Skeleton className='h-14 w-[80%]' />
<Skeleton className='h-14 w-[75%]' />
</ol>
);
};

View file

@ -1,5 +1,6 @@
import * as React from 'react';
import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react';
import Link from 'next/link';
import { cn } from '@/lib/utils';
import { ButtonProps, buttonVariants } from '@/components/ui/button';
@ -37,7 +38,7 @@ PaginationItem.displayName = 'PaginationItem';
type PaginationLinkProps = {
isActive?: boolean;
} & Pick<ButtonProps, 'size'> &
React.ComponentProps<'a'>;
React.ComponentProps<typeof Link>;
const PaginationLink = ({
className,
@ -45,7 +46,7 @@ const PaginationLink = ({
size = 'icon',
...props
}: PaginationLinkProps) => (
<a
<Link
aria-current={isActive ? 'page' : undefined}
className={cn(
buttonVariants({