Skip to content

Commit

Permalink
Paginate document logs table to improve page performance
Browse files Browse the repository at this point in the history
  • Loading branch information
andresgutgon committed Sep 26, 2024
1 parent 5eacfe1 commit 7798b60
Show file tree
Hide file tree
Showing 16 changed files with 706 additions and 429 deletions.
21 changes: 0 additions & 21 deletions apps/web/src/app/(private)/_data-access/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ApiKeysRepository } from '@latitude-data/core/repositories/apiKeysRepos
import {
CommitsRepository,
ConnectedEvaluationsRepository,
DocumentLogsRepository,
DocumentVersionsRepository,
EvaluationsRepository,
ProjectsRepository,
Expand Down Expand Up @@ -140,26 +139,6 @@ export const getDocumentByIdCached = cache(async (id: number) => {
return document
})

export const getDocumentLogsWithMetadataCached = cache(
async ({
documentUuid,
commit,
}: {
documentUuid: string
commit: Commit
}) => {
const { workspace } = await getCurrentUser()
const docsScope = new DocumentLogsRepository(workspace.id)
const result = await docsScope.getDocumentLogsWithMetadata({
documentUuid,
draft: commit,
})
const logs = result.unwrap()

return logs
},
)

export const getDocumentsFromMergedCommitsCache = cache(
async (workspaceId: number) => {
const docsScope = new DocumentVersionsRepository(workspaceId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ const ProviderLogMessages = ({
) as ProviderLogDto
if (!providerLog) {
return (
<div className='flex flex-col items-center justify-center rounded-lg border border-2 bg-secondary p-4 h-[480px]'>
<div className='flex flex-col items-center justify-center rounded-lg border-2 bg-secondary p-4 h-[480px]'>
<Text.H5M color='foregroundMuted'>
Select a log on the table to preview the messages here and import
</Text.H5M>
Expand All @@ -207,7 +207,7 @@ const ProviderLogMessages = ({
}

return (
<div className='rounded-lg border border-2 bg-secondary p-4 overflow-y-auto max-h-[480px]'>
<div className='rounded-lg border-2 bg-secondary p-4 overflow-y-auto max-h-[480px]'>
<Text.H5M>Messages</Text.H5M>
<div className='flex flex-col gap-2'>
{providerLog.messages.map((message, index) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
'use client'

import { DocumentLogWithMetadata } from '@latitude-data/core/repositories'
import {
Badge,
Expand Down Expand Up @@ -33,6 +31,7 @@ export const DocumentLogsTable = ({
<TableRow>
<TableHead>Time</TableHead>
<TableHead>Version</TableHead>
<TableHead>Origin</TableHead>
<TableHead>Custom Identifier</TableHead>
<TableHead>Duration</TableHead>
<TableHead>Tokens</TableHead>
Expand Down Expand Up @@ -75,6 +74,9 @@ export const DocumentLogsTable = ({
<Text.H5>{documentLog.commit.title}</Text.H5>
</div>
</TableCell>
<TableCell>
<Text.H4>{documentLog.source}</Text.H4>
</TableCell>
<TableCell>
<Text.H4>{documentLog.customIdentifier}</Text.H4>
</TableCell>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@

import { useState } from 'react'

import { IPagination } from '@latitude-data/core/lib/buildPagination'
import { DocumentLogWithMetadata } from '@latitude-data/core/repositories'
import WebPagination from '$/components/WebPagination'
import useProviderLogs from '$/stores/providerLogs'

import { DocumentLogInfo } from './DocumentLogInfo'
import { DocumentLogsTable } from './DocumentLogsTable'

export function DocumentLogs({
documentLogs,
pagination,
}: {
documentLogs: DocumentLogWithMetadata[]
pagination: IPagination
}) {
const [selectedLog, setSelectedLog] = useState<
DocumentLogWithMetadata | undefined
Expand All @@ -22,16 +26,18 @@ export function DocumentLogs({

return (
<div className='flex flex-row w-full h-full overflow-hidden gap-4'>
<div className='flex-grow min-w-0 h-full'>
<div className='flex flex-col flex-grow min-w-0 h-full gap-y-4'>
<DocumentLogsTable
documentLogs={documentLogs}
selectedLog={selectedLog}
setSelectedLog={setSelectedLog}
/>
<WebPagination {...pagination} />
</div>
{selectedLog && (
<div className='w-80 flex-shrink-0 flex flex-col border border-border rounded-lg px-4 pt-6 items-center'>
<DocumentLogInfo
key={pagination.currentPage}
documentLog={selectedLog}
providerLogs={providerLogs}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,34 +1,57 @@
import { TableBlankSlate, TableWithHeader } from '@latitude-data/web-ui'
import {
findCommitCached,
getDocumentLogsWithMetadataCached,
} from '$/app/(private)/_data-access'
buildPagination,
parsePage,
} from '@latitude-data/core/lib/buildPagination'
import { computeDocumentLogsWithMetadata } from '@latitude-data/core/services/documentLogs/computeDocumentLogsWithMetadata'
import { TableBlankSlate, TableWithHeader } from '@latitude-data/web-ui'
import { findCommitCached } from '$/app/(private)/_data-access'
import { getCurrentUser } from '$/services/auth/getCurrentUser'
import { ROUTES } from '$/services/routes'

import { DocumentLogs } from './_components/DocumentLogs'

const PAGE_SIZE = 25
export default async function DocumentPage({
params,
searchParams,
}: {
params: { projectId: string; commitUuid: string; documentUuid: string }
searchParams: { [key: string]: string | string[] | undefined }
}) {
const { workspace } = await getCurrentUser()
const projectId = Number(params.projectId)
const commitUuid = params.commitUuid
const commit = await findCommitCached({ projectId, uuid: commitUuid })
const logs = await getDocumentLogsWithMetadataCached({
const page = parsePage(searchParams.page)
const [rows, count] = await computeDocumentLogsWithMetadata({
workspaceId: workspace.id,
documentUuid: params.documentUuid,
commit,
draft: commit,
pagination: { page, pageSize: PAGE_SIZE },
})

const baseUrl = ROUTES.projects
.detail({ id: projectId })
.commits.detail({ uuid: commitUuid })
.documents.detail({ uuid: params.documentUuid }).logs.root
const pagination = buildPagination({
baseUrl,
count,
page,
pageSize: PAGE_SIZE,
})
const title = `${pagination.count} logs (page ${pagination.currentPage} of ${pagination.totalPages})`
return (
<div className='flex flex-col w-full h-full overflow-hidden p-6 gap-2 min-w-0'>
<TableWithHeader
title='Logs'
title={title}
table={
<>
{!logs.length && (
{!rows.length && (
<TableBlankSlate description='There are no logs for this prompt yet. Logs will appear here when you run the prompt for the first time.' />
)}
{logs.length > 0 && <DocumentLogs documentLogs={logs} />}
{rows.length > 0 && (
<DocumentLogs documentLogs={rows} pagination={pagination} />
)}
</>
}
/>
Expand Down
50 changes: 50 additions & 0 deletions apps/web/src/components/WebPagination/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { IPagination } from '@latitude-data/core/lib/buildPagination'
import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from '@latitude-data/web-ui'
import Link from 'next/link'

export default function WebPagination({
currentPage,
prevPage,
pageItems,
nextPage,
}: IPagination) {
return (
<Pagination aria-label='Pagination'>
<PaginationContent>
{prevPage && (
<Link href={prevPage.url}>
<PaginationPrevious />
</Link>
)}
{pageItems.map((item, idx) => {
return (
<PaginationItem key={idx}>
{item.type === 'page' ? (
<Link href={item.url}>
<PaginationLink isActive={item.value === currentPage}>
{item.value}
</PaginationLink>
</Link>
) : (
<PaginationEllipsis />
)}
</PaginationItem>
)
})}
{nextPage && (
<Link href={nextPage.url}>
<PaginationNext />
</Link>
)}
</PaginationContent>
</Pagination>
)
}
110 changes: 110 additions & 0 deletions packages/core/src/lib/buildPagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { isNumber } from 'lodash-es'

type ItemType = 'page' | 'ellipsis'
type PageItem<T extends ItemType> = T extends 'page'
? { type: T; value: number; url: string }
: { type: T; value: '...' }
export type IPagination = {
count: number
totalPages: number
currentPage: number
prevPage?: PageItem<'page'>
pageItems: (PageItem<'page'> | PageItem<'ellipsis'>)[]
nextPage?: PageItem<'page'>
}

function buildUrl({
baseUrl,
page,
limit,
}: {
baseUrl: string
page: number
limit: number
}) {
return `${baseUrl}?page=${page}&limit=${limit}`
}

export function buildPagination({
baseUrl,
count,
page,
pageSize,
pageItemsCount = 10,
}: {
baseUrl: string
count: number
page: number
pageSize: number
pageItemsCount?: number
}) {
const totalPages = Math.ceil(count / pageSize)
const pagination: IPagination = {
count,
totalPages,
currentPage: page,
prevPage:
page > 1
? {
type: 'page',
value: page - 1,
url: buildUrl({ baseUrl, page: page - 1, limit: pageSize }),
}
: undefined,
pageItems: [],
nextPage:
page < totalPages
? {
type: 'page',
value: page + 1,
url: buildUrl({ baseUrl, page: page + 1, limit: pageSize }),
}
: undefined,
}

for (let i = page - 1; i >= 1 && pagination.pageItems.length < 2; i--) {
pagination.pageItems.unshift({
type: 'page',
url: buildUrl({ baseUrl, page: i, limit: pageSize }),
value: i,
})
}

const prevItem = pagination.pageItems[0]
const prevPage = isNumber(prevItem?.value) ? prevItem.value : undefined
if (pagination.pageItems.length > 0 && prevPage && prevPage < page - 2) {
pagination.pageItems.push({ type: 'ellipsis', value: '...' })
}

pagination.pageItems.push({
type: 'page',
value: page,
url: buildUrl({ baseUrl, page, limit: pageSize }),
})

for (
let i = page + 1;
i <= totalPages && pagination.pageItems.length < pageItemsCount;
i++
) {
pagination.pageItems.push({
type: 'page',
value: i,
url: buildUrl({ baseUrl, page: i, limit: pageSize }),
})
}

const nextItem = pagination.pageItems[pagination.pageItems.length - 1]
const nextPage = isNumber(nextItem?.value) ? nextItem.value : undefined
if (pagination.pageItems.length > 0 && nextPage && nextPage > page + 1) {
pagination.pageItems.push({ type: 'ellipsis', value: '...' })
}

return pagination
}

export function parsePage(
page: string | string[] | number | undefined,
): number {
return typeof page === 'string' ? Number(page) : 1
}
5 changes: 3 additions & 2 deletions packages/core/src/repositories/commitsRepository/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,12 +156,13 @@ export class CommitsRepository extends Repository<
.where(and(eq(this.scope.projectId, project.id), filter))
.orderBy(desc(this.scope.createdAt))

const result = await Repository.paginateQuery({
const [rows] = await Repository.paginateQuery({
query: query.$dynamic(),
page,
pageSize,
})
return Result.ok(result)

return Result.ok(rows)
}

async getChanges(id: number, tx = database) {
Expand Down
21 changes: 1 addition & 20 deletions packages/core/src/repositories/documentLogsRepository/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { eq, getTableColumns } from 'drizzle-orm'

import { Commit, DocumentLog } from '../../browser'
import { NotFoundError, Result, TypedResult } from '../../lib'
import { NotFoundError, Result } from '../../lib'
import { commits, documentLogs, projects, workspaces } from '../../schema'
import { computeDocumentLogsWithMetadata } from '../../services/documentLogs'
import Repository from '../repository'

export type DocumentLogWithMetadata = DocumentLog & {
Expand Down Expand Up @@ -40,22 +39,4 @@ export class DocumentLogsRepository extends Repository<typeof tt, DocumentLog> {

return Result.ok(result[0]!)
}

// TODO: remove in favor of computeDocumentLogsWithMetadata
async getDocumentLogsWithMetadata({
documentUuid,
draft,
}: {
documentUuid: string
draft?: Commit
}): Promise<TypedResult<DocumentLogWithMetadata[], Error>> {
return computeDocumentLogsWithMetadata(
{
workspaceId: this.workspaceId,
documentUuid,
draft,
},
this.db,
)
}
}
Loading

0 comments on commit 7798b60

Please sign in to comment.