diff --git a/apps/web/src/actions/commits/fetchCommitsByProjectAction.ts b/apps/web/src/actions/commits/fetchCommitsByProjectAction.ts
index 14991a442..f0f7dac8c 100644
--- a/apps/web/src/actions/commits/fetchCommitsByProjectAction.ts
+++ b/apps/web/src/actions/commits/fetchCommitsByProjectAction.ts
@@ -1,6 +1,7 @@
'use server'
import { CommitStatus } from '@latitude-data/core/browser'
+import { paginateQuery } from '@latitude-data/core/lib/index'
import { CommitsRepository } from '@latitude-data/core/repositories'
import { z } from 'zod'
@@ -8,7 +9,6 @@ import { withProject } from '../procedures'
// Not really using pagination yet
const ULTRA_LARGE_PAGE_SIZE = 1000
-
export const fetchCommitsByProjectAction = withProject
.createServerAction()
.input(
@@ -20,12 +20,17 @@ export const fetchCommitsByProjectAction = withProject
{ type: 'json' },
)
.handler(async ({ input, ctx }) => {
- return new CommitsRepository(ctx.workspace.id)
- .getCommitsByProject({
- project: ctx.project,
- filterByStatus: input.status,
- page: input.page ?? 1,
- pageSize: input.pageSize ?? ULTRA_LARGE_PAGE_SIZE,
- })
- .then((r) => r.unwrap())
+ const repo = new CommitsRepository(ctx.workspace.id)
+ const { rows } = await paginateQuery({
+ dynamicQuery: repo
+ .getCommitsByProjectQuery({
+ project: ctx.project,
+ filterByStatus: input.status,
+ })
+ .$dynamic(),
+ defaultPaginate: {
+ pageSize: ULTRA_LARGE_PAGE_SIZE,
+ },
+ })
+ return rows
})
diff --git a/apps/web/src/actions/evaluations/computeEvaluationResultsWithMetadata.ts b/apps/web/src/actions/evaluations/computeEvaluationResultsWithMetadata.ts
index 1520853b9..7fe05fecd 100644
--- a/apps/web/src/actions/evaluations/computeEvaluationResultsWithMetadata.ts
+++ b/apps/web/src/actions/evaluations/computeEvaluationResultsWithMetadata.ts
@@ -1,10 +1,12 @@
'use server'
+import { paginateQuery } from '@latitude-data/core/lib/index'
import {
CommitsRepository,
+ EvaluationResultWithMetadata,
EvaluationsRepository,
} from '@latitude-data/core/repositories'
-import { computeEvaluationResultsWithMetadata } from '@latitude-data/core/services/evaluationResults/computeEvaluationResultsWithMetadata'
+import { computeEvaluationResultsWithMetadataQuery } from '@latitude-data/core/services/evaluationResults/computeEvaluationResultsWithMetadata'
import { z } from 'zod'
import { withProject } from '../procedures'
@@ -16,6 +18,8 @@ export const computeEvaluationResultsWithMetadataAction = withProject
evaluationId: z.number(),
documentUuid: z.string(),
commitUuid: z.string(),
+ page: z.string().nullable(),
+ pageSize: z.string().nullable(),
}),
)
.handler(async ({ input, ctx }) => {
@@ -29,12 +33,18 @@ export const computeEvaluationResultsWithMetadataAction = withProject
const commit = await commitsScope
.getCommitByUuid({ projectId: project.id, uuid: input.commitUuid })
.then((r) => r.unwrap())
+ const { rows } = await paginateQuery({
+ searchParams: {
+ page: input.page ?? undefined,
+ pageSize: input.pageSize ?? undefined,
+ },
+ dynamicQuery: computeEvaluationResultsWithMetadataQuery({
+ workspaceId: evaluation.workspaceId,
+ evaluation,
+ documentUuid,
+ draft: commit,
+ }).$dynamic(),
+ })
- return await computeEvaluationResultsWithMetadata({
- workspaceId: ctx.workspace.id,
- evaluation,
- documentUuid,
- draft: commit,
- limit: 1000,
- }).then((r) => r.unwrap())
+ return rows as EvaluationResultWithMetadata[]
})
diff --git a/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/Playground/Chat/index.tsx b/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/Playground/Chat/index.tsx
index 3dee36dc7..7e6da5a2e 100644
--- a/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/Playground/Chat/index.tsx
+++ b/apps/web/src/app/(private)/evaluations/(evaluation)/[evaluationUuid]/editor/_components/EvaluationEditor/Editor/Playground/Chat/index.tsx
@@ -144,7 +144,7 @@ export default function Chat({
Prompt
Prompt
-
- {children}
-
+ {children}
)
}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/DatasetForm/index.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/DatasetForm/index.tsx
similarity index 100%
rename from apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/DatasetForm/index.tsx
rename to apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/DatasetForm/index.tsx
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/index.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/index.tsx
similarity index 80%
rename from apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/index.tsx
rename to apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/index.tsx
index c51268be8..c8d660b48 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/index.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/index.tsx
@@ -1,45 +1,34 @@
-'use client'
-
import { useCallback } from 'react'
import { DocumentVersion, EvaluationDto } from '@latitude-data/core/browser'
import { Button, CloseTrigger, Modal } from '@latitude-data/web-ui'
import { useMetadata } from '$/hooks/useMetadata'
-import { useNavigate } from '$/hooks/useNavigate'
-import { ROUTES } from '$/services/routes'
import DatasetForm from './DatasetForm'
import { useRunBatch } from './useRunBatch'
import { useRunBatchForm } from './useRunBatchForm'
export default function CreateBatchEvaluationModal({
+ open,
+ onClose,
document,
evaluation,
projectId,
commitUuid,
}: {
+ open: boolean
+ onClose: () => void
projectId: string
commitUuid: string
document: DocumentVersion
evaluation: EvaluationDto
}) {
- const navigate = useNavigate()
- const documentUuid = document.documentUuid
- const goToDetail = useCallback(() => {
- navigate.push(
- ROUTES.projects
- .detail({ id: Number(projectId) })
- .commits.detail({ uuid: commitUuid })
- .documents.detail({ uuid: documentUuid })
- .evaluations.detail(evaluation.id).root,
- )
- }, [evaluation.id, projectId, commitUuid, documentUuid])
const { runBatch, errors, isRunningBatch } = useRunBatch({
document,
projectId,
commitUuid,
onSuccess: () => {
- goToDetail()
+ onClose()
},
})
@@ -73,11 +62,11 @@ export default function CreateBatchEvaluationModal({
return (
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/useRunBatch.ts b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/useRunBatch.ts
similarity index 100%
rename from apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/useRunBatch.ts
rename to apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/useRunBatch.ts
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/useRunBatchForm.ts b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/useRunBatchForm.ts
similarity index 100%
rename from apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/_components/CreateBatchEvaluationModal/useRunBatchForm.ts
rename to apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/CreateBatchEvaluationModal/useRunBatchForm.ts
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/index.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/index.tsx
index 8fedfd3ff..13ef38a46 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/index.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/Actions/index.tsx
@@ -1,10 +1,11 @@
'use client'
+import { useCallback, useState } from 'react'
+
import { EvaluationDto } from '@latitude-data/core/browser'
-import { TableWithHeader } from '@latitude-data/web-ui'
-import { ROUTES } from '$/services/routes'
-import Link from 'next/link'
+import { TableWithHeader, useCurrentDocument } from '@latitude-data/web-ui'
+import CreateBatchEvaluationModal from './CreateBatchEvaluationModal'
import LiveEvaluationToggle from './LiveEvaluationToggle'
export function Actions({
@@ -18,21 +19,27 @@ export function Actions({
commitUuid: string
documentUuid: string
}) {
- const href = ROUTES.projects
- .detail({ id: Number(projectId) })
- .commits.detail({ uuid: commitUuid })
- .documents.detail({ uuid: documentUuid })
- .evaluations.detail(evaluation.id).createBatch
-
+ const document = useCurrentDocument()
+ const [open, setOpen] = useState(false)
+ const onClose = useCallback(() => setOpen(false), [])
+ const onOpen = useCallback(() => setOpen(true), [])
return (
-
-
Run batch evaluation
-
+
+ Run batch evaluation
+
+
)
}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultInfo/Messages.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultInfo/Messages.tsx
index 0b5ade8d3..22ea585b8 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultInfo/Messages.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultInfo/Messages.tsx
@@ -23,9 +23,8 @@ export function EvaluationResultMessages({
if (!providerLog) return null
return (
-
+
(null)
const [selectedTab, setSelectedTab] = useState('metadata')
const [selected, setSelected] = useState(null)
const onClickOpen = useCallback(async () => {
setSelected(evaluationResult.documentLogId)
}, [evaluationResult.documentLogId])
+ const height = useDynamicHeight({ ref, paddingBottom: 16 })
return (
<>
-
-
-
+
+
+
{selectedTab === 'metadata' && (
)}
+
+
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultsTable.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultsTable.tsx
index c79d6172c..40d67d301 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultsTable.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/EvaluationResultsTable.tsx
@@ -1,9 +1,11 @@
+import { useRef } from 'react'
import { capitalize } from 'lodash-es'
import {
EvaluationDto,
EvaluationResultableType,
} from '@latitude-data/core/browser'
+import { IPagination } from '@latitude-data/core/lib/pagination/buildPagination'
import { EvaluationResultWithMetadata } from '@latitude-data/core/repositories'
import {
Badge,
@@ -18,6 +20,12 @@ import {
Text,
} from '@latitude-data/web-ui'
import { formatCostInMillicents, relativeTime } from '$/app/_lib/formatUtils'
+import { TablePaginationFooter } from '$/components/TablePaginationFooter'
+import useDynamicHeight from '$/hooks/useDynamicHeight'
+
+function countLabel(count: number) {
+ return `${count} evaluation results`
+}
export const ResultCellContent = ({
evaluation,
@@ -55,17 +63,21 @@ type EvaluationResultRow = EvaluationResultWithMetadata & {
}
export const EvaluationResultsTable = ({
evaluation,
+ pagination,
evaluationResults,
selectedResult,
setSelectedResult,
}: {
evaluation: EvaluationDto
+ pagination: IPagination
evaluationResults: EvaluationResultRow[]
selectedResult: EvaluationResultRow | undefined
setSelectedResult: (log: EvaluationResultWithMetadata | undefined) => void
}) => {
+ const ref = useRef
(null)
+ const height = useDynamicHeight({ ref, paddingBottom: 16 })
return (
-
+
Time
@@ -76,7 +88,7 @@ export const EvaluationResultsTable = ({
Tokens
-
+
{evaluationResults.map((evaluationResult) => (
))}
+
)
}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/index.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/index.tsx
index 91bb72847..68c405264 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/index.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_components/EvaluationResults/index.tsx
@@ -3,6 +3,7 @@
import { useState } from 'react'
import { EvaluationDto } from '@latitude-data/core/browser'
+import { IPagination } from '@latitude-data/core/lib/pagination/buildPagination'
import { type EvaluationResultWithMetadata } from '@latitude-data/core/repositories'
import {
TableBlankSlate,
@@ -19,6 +20,7 @@ import { DocumentRoutes, ROUTES } from '$/services/routes'
import useEvaluationResultsWithMetadata from '$/stores/evaluationResultsWithMetadata'
import { useProviderLog } from '$/stores/providerLogs'
import Link from 'next/link'
+import { useSearchParams } from 'next/navigation'
import { EvaluationResultInfo } from './EvaluationResultInfo'
import { EvaluationResultsTable } from './EvaluationResultsTable'
@@ -27,9 +29,11 @@ import { EvaluationStatusBanner } from './EvaluationStatusBanner'
export function EvaluationResults({
evaluation,
evaluationResults: serverData,
+ pagination,
}: {
evaluation: EvaluationDto
evaluationResults: EvaluationResultWithMetadata[]
+ pagination: IPagination
}) {
const { project } = useCurrentProject()
const { commit } = useCurrentCommit()
@@ -38,12 +42,17 @@ export function EvaluationResults({
EvaluationResultWithMetadata | undefined
>(undefined)
const { data: providerLog } = useProviderLog(selectedResult?.providerLogId)
+ const searchParams = useSearchParams()
+ const page = searchParams.get('page')
+ const pageSize = searchParams.get('pageSize')
const { data: evaluationResults, mutate } = useEvaluationResultsWithMetadata(
{
evaluationId: evaluation.id,
documentUuid: document.documentUuid,
commitUuid: commit.uuid,
projectId: project.id,
+ page,
+ pageSize,
},
{
fallbackData: serverData,
@@ -103,6 +112,7 @@ export function EvaluationResults({
evaluationResults={evaluationResults}
selectedResult={selectedResult}
setSelectedResult={setSelectedResult}
+ pagination={pagination}
/>
)}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_lib/fetchEvaluationCached.ts b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_lib/fetchEvaluationCached.ts
new file mode 100644
index 000000000..2cb5e40a3
--- /dev/null
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/_lib/fetchEvaluationCached.ts
@@ -0,0 +1,10 @@
+import { cache } from 'react'
+
+import { EvaluationsRepository } from '@latitude-data/core/repositories'
+import { getCurrentUser } from '$/services/auth/getCurrentUser'
+
+export const fetchEvaluationCached = cache(async (id: number) => {
+ const { workspace } = await getCurrentUser()
+ const evaluationScope = new EvaluationsRepository(workspace.id)
+ return evaluationScope.find(id).then((r) => r.unwrap())
+})
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/page.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/page.tsx
deleted file mode 100644
index 5c5fb5555..000000000
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/create-batch/page.tsx
+++ /dev/null
@@ -1,38 +0,0 @@
-import { EvaluationsRepository } from '@latitude-data/core/repositories'
-import { getDocumentByUuidCached } from '$/app/(private)/_data-access'
-import { getCurrentUser } from '$/services/auth/getCurrentUser'
-
-import CreateBatchEvaluationModal from './_components/CreateBatchEvaluationModal'
-
-export default async function ConnectionEvaluationModal({
- params,
-}: {
- params: {
- projectId: string
- commitUuid: string
- documentUuid: string
- evaluationId: string
- }
-}) {
- const { workspace } = await getCurrentUser()
- const evaluationScope = new EvaluationsRepository(workspace.id)
- const evaluation = await evaluationScope
- .find(params.evaluationId)
- .then((r) => r.unwrap())
- const projectId = Number(params.projectId)
- const documentUuid = params.documentUuid
- const commitUuid = params.commitUuid
- const document = await getDocumentByUuidCached({
- projectId,
- commitUuid,
- documentUuid,
- })
- return (
-
- )
-}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/layout.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/layout.tsx
index 431925feb..2461aca7a 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/layout.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/layout.tsx
@@ -8,8 +8,6 @@ import {
EvaluationModalValue,
EvaluationResultableType,
} from '@latitude-data/core/browser'
-import { EvaluationsRepository } from '@latitude-data/core/repositories'
-import { computeEvaluationResultsWithMetadata } from '@latitude-data/core/services/evaluationResults/computeEvaluationResultsWithMetadata'
import {
getEvaluationMeanValueQuery,
getEvaluationModalValueQuery,
@@ -24,8 +22,8 @@ import { ROUTES } from '$/services/routes'
import Link from 'next/link'
import { Actions } from './_components/Actions'
-import { EvaluationResults } from './_components/EvaluationResults'
import { MetricsSummary } from './_components/MetricsSummary'
+import { fetchEvaluationCached } from './_lib/fetchEvaluationCached'
const TYPE_TEXT: Record = {
[EvaluationResultableType.Text]: 'Text',
@@ -94,23 +92,11 @@ export default async function ConnectedEvaluationLayout({
}
}) {
const { workspace } = await getCurrentUser()
- const evaluationScope = new EvaluationsRepository(workspace.id)
- const evaluation = await evaluationScope
- .find(params.evaluationId)
- .then((r) => r.unwrap())
-
+ const evaluation = await fetchEvaluationCached(Number(params.evaluationId))
const commit = await findCommitCached({
projectId: Number(params.projectId),
uuid: params.commitUuid,
})
-
- const evaluationResults = await computeEvaluationResultsWithMetadata({
- workspaceId: evaluation.workspaceId,
- evaluation,
- documentUuid: params.documentUuid,
- draft: commit,
- limit: 1000,
- }).then((r) => r.unwrap())
const isNumeric =
evaluation.configuration.type == EvaluationResultableType.Number
const data = await fetchData({
@@ -120,10 +106,8 @@ export default async function ConnectedEvaluationLayout({
isNumeric,
commit,
})
-
return (
-
- {children}
+
)
}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/page.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/page.tsx
index 603e00efb..468d0ffe2 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/page.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/evaluations/[evaluationId]/page.tsx
@@ -1,3 +1,57 @@
-export default function ConnectedEvaluationsPage() {
- return null // --> layout.tsx
+import { paginateQuery } from '@latitude-data/core/lib/index'
+import { QueryParams } from '@latitude-data/core/lib/pagination/buildPaginatedUrl'
+import { computeEvaluationResultsWithMetadataQuery } from '@latitude-data/core/services/evaluationResults/computeEvaluationResultsWithMetadata'
+import { findCommitCached } from '$/app/(private)/_data-access'
+import { ROUTES } from '$/services/routes'
+
+import { EvaluationResults } from './_components/EvaluationResults'
+import { fetchEvaluationCached } from './_lib/fetchEvaluationCached'
+
+function pageUrl(params: {
+ projectId: string
+ commitUuid: string
+ documentUuid: string
+ evaluationId: string
+}) {
+ return ROUTES.projects
+ .detail({ id: Number(params.projectId) })
+ .commits.detail({ uuid: params.commitUuid })
+ .documents.detail({ uuid: params.documentUuid })
+ .evaluations.detail(Number(params.evaluationId)).root
+}
+
+export default async function ConnectedEvaluationPage({
+ params,
+ searchParams,
+}: {
+ params: {
+ projectId: string
+ commitUuid: string
+ documentUuid: string
+ evaluationId: string
+ }
+ searchParams: QueryParams
+}) {
+ const evaluation = await fetchEvaluationCached(Number(params.evaluationId))
+ const commit = await findCommitCached({
+ projectId: Number(params.projectId),
+ uuid: params.commitUuid,
+ })
+ const { rows, pagination } = await paginateQuery({
+ searchParams,
+ pageUrl: { base: pageUrl(params) },
+ dynamicQuery: computeEvaluationResultsWithMetadataQuery({
+ workspaceId: evaluation.workspaceId,
+ evaluation,
+ documentUuid: params.documentUuid,
+ draft: commit,
+ }).$dynamic(),
+ })
+ return (
+
+ )
}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogInfo/Messages.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogInfo/Messages.tsx
index 02ea269fb..1091b1cff 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogInfo/Messages.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogInfo/Messages.tsx
@@ -24,7 +24,7 @@ export function DocumentLogMessages({
if (!providerLogs) return null
return (
-
+
('metadata')
+ const ref = useRef(null)
+ const height = useDynamicHeight({ ref, paddingBottom: 16 })
return (
- <>
-
-
+
+
+
{isLoading ? (
) : (
@@ -71,6 +90,6 @@ export function DocumentLogInfo({
>
)}
- >
+
)
}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogsTable.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogsTable.tsx
index fe180536d..687dd5d19 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogsTable.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/DocumentLogsTable.tsx
@@ -1,3 +1,6 @@
+import { useRef } from 'react'
+
+import { IPagination } from '@latitude-data/core/lib/pagination/buildPagination'
import { DocumentLogWithMetadata } from '@latitude-data/core/repositories'
import {
Badge,
@@ -15,18 +18,28 @@ import {
formatDuration,
relativeTime,
} from '$/app/_lib/formatUtils'
+import { TablePaginationFooter } from '$/components/TablePaginationFooter'
+import useDynamicHeight from '$/hooks/useDynamicHeight'
+
+function countLabel(count: number) {
+ return `${count} logs`
+}
export const DocumentLogsTable = ({
documentLogs,
selectedLog,
setSelectedLog,
+ pagination,
}: {
documentLogs: DocumentLogWithMetadata[]
selectedLog: DocumentLogWithMetadata | undefined
setSelectedLog: (log: DocumentLogWithMetadata | undefined) => void
+ pagination: IPagination
}) => {
+ const ref = useRef
(null)
+ const height = useDynamicHeight({ ref, paddingBottom: 16 })
return (
-
+
Time
@@ -38,7 +51,7 @@ export const DocumentLogsTable = ({
Cost
-
+
{documentLogs.map((documentLog, idx) => (
))}
+
)
}
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/index.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/index.tsx
index cc10910e9..04d8f3b6a 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/index.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/_components/DocumentLogs/index.tsx
@@ -2,9 +2,8 @@
import { useState } from 'react'
-import { IPagination } from '@latitude-data/core/lib/buildPagination'
+import { IPagination } from '@latitude-data/core/lib/pagination/buildPagination'
import { DocumentLogWithMetadata } from '@latitude-data/core/repositories'
-import WebPagination from '$/components/WebPagination'
import useProviderLogs from '$/stores/providerLogs'
import { DocumentLogInfo } from './DocumentLogInfo'
@@ -25,23 +24,21 @@ export function DocumentLogs({
})
return (
-
+
-
{selectedLog && (
-
-
-
+
)}
)
diff --git a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/page.tsx b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/page.tsx
index 12ecc4794..2ee6010df 100644
--- a/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/page.tsx
+++ b/apps/web/src/app/(private)/projects/[projectId]/versions/[commitUuid]/documents/[documentUuid]/logs/page.tsx
@@ -1,8 +1,6 @@
-import {
- buildPagination,
- parsePage,
-} from '@latitude-data/core/lib/buildPagination'
-import { computeDocumentLogsWithMetadata } from '@latitude-data/core/services/documentLogs/computeDocumentLogsWithMetadata'
+import { QueryParams } from '@latitude-data/core/lib/pagination/buildPaginatedUrl'
+import { paginateQuery } from '@latitude-data/core/lib/pagination/paginate'
+import { computeDocumentLogsWithMetadataQuery } 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'
@@ -10,40 +8,41 @@ import { ROUTES } from '$/services/routes'
import { DocumentLogs } from './_components/DocumentLogs'
-const PAGE_SIZE = 25
+function pageUrl(params: {
+ projectId: string
+ commitUuid: string
+ documentUuid: string
+}) {
+ return ROUTES.projects
+ .detail({ id: Number(params.projectId) })
+ .commits.detail({ uuid: params.commitUuid })
+ .documents.detail({ uuid: params.documentUuid }).logs.root
+}
+
export default async function DocumentPage({
params,
searchParams,
}: {
params: { projectId: string; commitUuid: string; documentUuid: string }
- searchParams: { [key: string]: string | string[] | undefined }
+ searchParams: QueryParams
}) {
const { workspace } = await getCurrentUser()
const projectId = Number(params.projectId)
const commitUuid = params.commitUuid
const commit = await findCommitCached({ projectId, uuid: commitUuid })
- const page = parsePage(searchParams.page)
- const [rows, count] = await computeDocumentLogsWithMetadata({
- workspaceId: workspace.id,
- documentUuid: params.documentUuid,
- 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 { rows, pagination } = await paginateQuery({
+ searchParams,
+ pageUrl: { base: pageUrl(params) },
+ dynamicQuery: computeDocumentLogsWithMetadataQuery({
+ workspaceId: workspace.id,
+ documentUuid: params.documentUuid,
+ draft: commit,
+ }).$dynamic(),
})
- const title = `${pagination.count} logs (page ${pagination.currentPage} of ${pagination.totalPages})`
return (
{!rows.length && (
diff --git a/apps/web/src/components/TablePaginationFooter/GoToPageInput/index.tsx b/apps/web/src/components/TablePaginationFooter/GoToPageInput/index.tsx
new file mode 100644
index 000000000..5fdfa89c0
--- /dev/null
+++ b/apps/web/src/components/TablePaginationFooter/GoToPageInput/index.tsx
@@ -0,0 +1,38 @@
+'use client'
+
+import { FormEvent, useCallback } from 'react'
+
+import { buildPaginatedUrl } from '@latitude-data/core/lib/pagination/buildPaginatedUrl'
+import { IPagination } from '@latitude-data/core/lib/pagination/buildPagination'
+import { Input } from '@latitude-data/web-ui'
+import { useNavigate } from '$/hooks/useNavigate'
+
+export function GoToPageInput({ pagination }: { pagination: IPagination }) {
+ const router = useNavigate()
+ const onSubmit = useCallback((event: FormEvent) => {
+ event.preventDefault()
+
+ const goToPage = new FormData(event.currentTarget).get('page')
+ const queryParams = window.location.search
+ router.push(
+ buildPaginatedUrl({
+ baseUrl: pagination.baseUrl,
+ page: Number(goToPage),
+ pageSize: pagination.pageSize,
+ queryParams,
+ }),
+ )
+ }, [])
+ return (
+
+ )
+}
diff --git a/apps/web/src/components/TablePaginationFooter/index.tsx b/apps/web/src/components/TablePaginationFooter/index.tsx
new file mode 100644
index 000000000..6945483ef
--- /dev/null
+++ b/apps/web/src/components/TablePaginationFooter/index.tsx
@@ -0,0 +1,72 @@
+import { IPagination } from '@latitude-data/core/lib/pagination/buildPagination'
+import {
+ Button,
+ TableCell,
+ TableFooter,
+ TableRow,
+ Text,
+} from '@latitude-data/web-ui'
+import { GoToPageInput } from '$/components/TablePaginationFooter/GoToPageInput'
+import Link from 'next/link'
+
+function NavLink({
+ url,
+ direction,
+}: {
+ url?: string
+ direction: 'prev' | 'next'
+}) {
+ const button = (
+
+ )
+ if (!url) return button
+
+ return {button}
+}
+
+export function TablePaginationFooter({
+ colSpan,
+ pagination,
+ countLabel,
+}: {
+ colSpan: number
+ pagination: IPagination
+ countLabel?: (count: number) => string
+}) {
+ return (
+
+
+
+
+
+ {countLabel ? countLabel(pagination.count) : pagination.count}{' '}
+
+
+
+
+
+
Page
+
+
+
+
+ of {pagination.totalPages}
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/apps/web/src/components/WebPagination/index.tsx b/apps/web/src/components/WebPagination/index.tsx
deleted file mode 100644
index 603cf5fae..000000000
--- a/apps/web/src/components/WebPagination/index.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-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 (
-
-
- {prevPage && (
-
-
-
- )}
- {pageItems.map((item, idx) => {
- return (
-
- {item.type === 'page' ? (
-
-
- {item.value}
-
-
- ) : (
-
- )}
-
- )
- })}
- {nextPage && (
-
-
-
- )}
-
-
- )
-}
diff --git a/apps/web/src/components/layouts/AppLayout/index.tsx b/apps/web/src/components/layouts/AppLayout/index.tsx
index b86cb6d91..f1031fb95 100644
--- a/apps/web/src/components/layouts/AppLayout/index.tsx
+++ b/apps/web/src/components/layouts/AppLayout/index.tsx
@@ -22,7 +22,7 @@ export default function AppLayout({
navigationLinks={navigationLinks}
currentUser={currentUser}
/>
- {children}
+ {children}
)
}
diff --git a/apps/web/src/hooks/useDynamicHeight.ts b/apps/web/src/hooks/useDynamicHeight.ts
new file mode 100644
index 000000000..6b5231828
--- /dev/null
+++ b/apps/web/src/hooks/useDynamicHeight.ts
@@ -0,0 +1,42 @@
+import { RefObject, useCallback, useEffect, useState } from 'react'
+
+function useDynamicHeight({
+ ref,
+ paddingBottom,
+}: {
+ ref: RefObject
+ paddingBottom?: number
+}) {
+ const [height, setHeight] = useState('auto')
+
+ const calculateHeight = useCallback(
+ (element: HTMLElement) => {
+ const topPosition = element.getBoundingClientRect().top
+ const windowHeight = paddingBottom
+ ? window.innerHeight - paddingBottom
+ : window.innerHeight
+ setHeight(windowHeight - topPosition)
+ },
+ [setHeight, paddingBottom],
+ )
+
+ useEffect(() => {
+ const element = ref.current
+ if (!element) return
+
+ calculateHeight(element)
+
+ const resizeObserver = new ResizeObserver(() => {
+ calculateHeight(element)
+ })
+
+ resizeObserver.observe(document.body)
+ return () => {
+ resizeObserver.disconnect()
+ }
+ }, [ref])
+
+ return height
+}
+
+export default useDynamicHeight
diff --git a/apps/web/src/stores/evaluationResultsWithMetadata.ts b/apps/web/src/stores/evaluationResultsWithMetadata.ts
index 7381564d6..e12330a7d 100644
--- a/apps/web/src/stores/evaluationResultsWithMetadata.ts
+++ b/apps/web/src/stores/evaluationResultsWithMetadata.ts
@@ -11,11 +11,15 @@ export default function useEvaluationResultsWithMetadata(
documentUuid,
commitUuid,
projectId,
+ page,
+ pageSize,
}: {
evaluationId: number
documentUuid: string
commitUuid: string
projectId: number
+ page: string | null
+ pageSize: string | null
},
{ fallbackData }: SWRConfiguration = {},
) {
@@ -26,6 +30,8 @@ export default function useEvaluationResultsWithMetadata(
documentUuid,
commitUuid,
projectId,
+ page,
+ pageSize,
})
if (error) {
@@ -38,9 +44,17 @@ export default function useEvaluationResultsWithMetadata(
}
return data
- }, [commitUuid, documentUuid, evaluationId, projectId, toast])
+ }, [commitUuid, documentUuid, evaluationId, projectId, toast, page, pageSize])
const { data = EMPTY_ARRAY, mutate } = useSWR(
- ['evaluationResults', evaluationId, documentUuid, commitUuid, projectId],
+ [
+ 'evaluationResults',
+ evaluationId,
+ documentUuid,
+ commitUuid,
+ projectId,
+ page,
+ pageSize,
+ ],
fetcher,
{ fallbackData },
)
diff --git a/apps/websockets/src/server.ts b/apps/websockets/src/server.ts
index 8a3ab9f9b..bc0e9b6aa 100644
--- a/apps/websockets/src/server.ts
+++ b/apps/websockets/src/server.ts
@@ -131,11 +131,13 @@ workers.on('connection', (socket) => {
const workspace = buildWorkspaceRoom({ workspaceId })
web.to(workspace).emit('evaluationStatus', data)
})
+
socket.on('evaluationResultCreated', (args) => {
const { workspaceId, data } = args
const workspace = buildWorkspaceRoom({ workspaceId })
web.to(workspace).emit('evaluationResultCreated', data)
})
+
socket.on('documentLogCreated', (args) => {
const { workspaceId, data } = args
const workspace = buildWorkspaceRoom({ workspaceId })
diff --git a/packages/core/src/events/handlers/createEvaluationResultJob.ts b/packages/core/src/events/handlers/createEvaluationResultJob.ts
index c209edf41..133febbf2 100644
--- a/packages/core/src/events/handlers/createEvaluationResultJob.ts
+++ b/packages/core/src/events/handlers/createEvaluationResultJob.ts
@@ -46,9 +46,7 @@ export const createEvaluationResultJob = async ({
const result = await baseQuery
.where(eq(evaluationResultsScope.id, evaluationResult.id))
.limit(1)
-
- const evaluationResultWithMetadata = result[0]!
-
+ const row = result[0]!
websockets.emit('evaluationResultCreated', {
workspaceId: evaluation.workspaceId,
data: {
@@ -56,7 +54,7 @@ export const createEvaluationResultJob = async ({
workspaceId: evaluation.workspaceId,
evaluationId: evaluation.id,
evaluationResultId: evaluationResult.id,
- row: evaluationResultWithMetadata,
+ row,
},
})
}
diff --git a/packages/core/src/lib/buildPagination.ts b/packages/core/src/lib/buildPagination.ts
deleted file mode 100644
index 6e790e0eb..000000000
--- a/packages/core/src/lib/buildPagination.ts
+++ /dev/null
@@ -1,110 +0,0 @@
-import { isNumber } from 'lodash-es'
-
-type ItemType = 'page' | 'ellipsis'
-type PageItem = 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
-}
diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts
index 79f8940a4..81c3a8f6b 100644
--- a/packages/core/src/lib/index.ts
+++ b/packages/core/src/lib/index.ts
@@ -4,3 +4,4 @@ export * from './Result'
export * from './errors'
export * from './commonTypes'
export * from './disk'
+export * from './pagination/paginate'
diff --git a/packages/core/src/lib/pagination/buildPaginatedUrl.ts b/packages/core/src/lib/pagination/buildPaginatedUrl.ts
new file mode 100644
index 000000000..376b302d0
--- /dev/null
+++ b/packages/core/src/lib/pagination/buildPaginatedUrl.ts
@@ -0,0 +1,32 @@
+export type QueryParams = { [key: string]: string | string[] | undefined }
+
+export function parseSearchParams(
+ searchParams: QueryParams | string | undefined,
+) {
+ if (typeof searchParams === 'string') {
+ const searchParamsInstance = new URLSearchParams(searchParams)
+ return Object.fromEntries(searchParamsInstance)
+ }
+
+ return searchParams ?? {}
+}
+
+export function buildPaginatedUrl({
+ baseUrl,
+ page,
+ pageSize,
+ queryParams,
+}: {
+ baseUrl: string
+ page: number
+ pageSize: number
+ queryParams?: QueryParams | string
+}) {
+ const queryString = new URLSearchParams({
+ ...parseSearchParams(queryParams),
+ page: String(page),
+ pageSize: String(pageSize),
+ }).toString()
+
+ return `${baseUrl}?${queryString}`
+}
diff --git a/packages/core/src/lib/pagination/buildPagination.ts b/packages/core/src/lib/pagination/buildPagination.ts
new file mode 100644
index 000000000..98e92ca38
--- /dev/null
+++ b/packages/core/src/lib/pagination/buildPagination.ts
@@ -0,0 +1,79 @@
+import {
+ buildPaginatedUrl,
+ parseSearchParams,
+ QueryParams,
+} from './buildPaginatedUrl'
+
+export type PaginationArgs = {
+ page?: number
+ pageSize?: number
+}
+
+function parsePage(page: string | string[] | number | undefined): number {
+ return typeof page === 'string' ? Number(page) : 1
+}
+
+export type IPagination = ReturnType
+
+export function getPaginationParamsWithDefaults({
+ defaultPaginate,
+ searchParams,
+}: {
+ defaultPaginate?: Exclude
+ searchParams?: QueryParams | string
+}) {
+ const params = parseSearchParams(searchParams)
+ return {
+ page: parsePage(params?.page),
+ pageSize: params?.pageSize
+ ? Number(params.pageSize)
+ : (defaultPaginate?.pageSize ?? 25),
+ }
+}
+
+export function buildPagination({
+ baseUrl,
+ count,
+ queryParams,
+ page,
+ pageSize,
+}: {
+ baseUrl: string
+ count: number
+ queryParams?: QueryParams | string | undefined
+ page: number
+ pageSize: number
+}) {
+ const totalPages = Math.ceil(count / pageSize)
+ return {
+ page,
+ baseUrl,
+ pageSize,
+ count,
+ totalPages,
+ prevPage:
+ page > 1
+ ? {
+ value: page - 1,
+ url: buildPaginatedUrl({
+ baseUrl,
+ page: page - 1,
+ pageSize,
+ queryParams,
+ }),
+ }
+ : undefined,
+ nextPage:
+ page < totalPages
+ ? {
+ value: page + 1,
+ url: buildPaginatedUrl({
+ baseUrl,
+ page: page + 1,
+ pageSize,
+ queryParams,
+ }),
+ }
+ : undefined,
+ }
+}
diff --git a/packages/core/src/lib/pagination/paginate.ts b/packages/core/src/lib/pagination/paginate.ts
new file mode 100644
index 000000000..7850a93dc
--- /dev/null
+++ b/packages/core/src/lib/pagination/paginate.ts
@@ -0,0 +1,70 @@
+import { sql } from 'drizzle-orm'
+import type { PgSelect } from 'drizzle-orm/pg-core'
+
+import { QueryParams } from './buildPaginatedUrl'
+import {
+ buildPagination,
+ getPaginationParamsWithDefaults,
+ PaginationArgs,
+} from './buildPagination'
+
+/**
+ * This use $dynamic() query
+ * https://orm.drizzle.team/docs/dynamic-query-building
+ */
+async function paginateQuerySql({
+ dynamicQuery,
+ page = 1,
+ pageSize = 20,
+}: {
+ dynamicQuery: T
+} & PaginationArgs) {
+ // @ts-ignore
+ dynamicQuery.config.fields = {
+ // @ts-ignore
+ ...dynamicQuery.config.fields,
+ __count: sql`count(*) over()`,
+ }
+ const rows = await dynamicQuery.limit(pageSize).offset((page - 1) * pageSize)
+ const count = rows[0]?.__count ? Number(rows[0]?.__count) : 0
+ return { rows, count }
+}
+
+/**
+ * TODO: Add tests
+ */
+export async function paginateQuery({
+ dynamicQuery,
+ pageUrl,
+ searchParams,
+ defaultPaginate,
+}: {
+ /**
+ * IMPORTANT:
+ * You need to use $dynamic() in your query
+ * Example: `yourQuery.$dynamic()`
+ */
+ dynamicQuery: T
+ pageUrl?: { base?: string; queryParams?: Record }
+ searchParams?: QueryParams | string
+ defaultPaginate?: Exclude
+}) {
+ const { page, pageSize } = getPaginationParamsWithDefaults({
+ defaultPaginate,
+ searchParams,
+ })
+ const { rows, count } = await paginateQuerySql({
+ dynamicQuery,
+ page,
+ pageSize,
+ })
+ const pagination = buildPagination({
+ baseUrl: pageUrl?.base ?? '',
+ count,
+ queryParams: searchParams,
+ page,
+ pageSize,
+ })
+
+ return { rows, pagination }
+}
diff --git a/packages/core/src/repositories/commitsRepository/index.test.ts b/packages/core/src/repositories/commitsRepository/index.test.ts
index 5d1f54bad..5d303f1ee 100644
--- a/packages/core/src/repositories/commitsRepository/index.test.ts
+++ b/packages/core/src/repositories/commitsRepository/index.test.ts
@@ -48,42 +48,24 @@ describe('Commits by project', () => {
})
it('gets all commits', async () => {
- const list = await repository
- .getCommitsByProject({ project })
- .then((r) => r.unwrap())
+ const list = await repository.getCommitsByProjectQuery({ project })
expect(list).toHaveLength(11)
})
it('get merged commits', async () => {
- const list = await repository
- .getCommitsByProject({
- project,
- filterByStatus: CommitStatus.Merged,
- })
- .then((r) => r.unwrap())
+ const list = await repository.getCommitsByProjectQuery({
+ project,
+ filterByStatus: CommitStatus.Merged,
+ })
expect(list).toHaveLength(3)
})
it('get drafts commits', async () => {
- const list = await repository
- .getCommitsByProject({
- project,
- filterByStatus: CommitStatus.Draft,
- })
- .then((r) => r.unwrap())
+ const list = await repository.getCommitsByProjectQuery({
+ project,
+ filterByStatus: CommitStatus.Draft,
+ })
expect(list).toHaveLength(8)
})
-
- it('get first page of drafts commits', async () => {
- const list = await repository
- .getCommitsByProject({
- project,
- filterByStatus: CommitStatus.Draft,
- page: 1,
- pageSize: 5,
- })
- .then((r) => r.unwrap())
- expect(list).toHaveLength(5)
- })
})
diff --git a/packages/core/src/repositories/commitsRepository/index.ts b/packages/core/src/repositories/commitsRepository/index.ts
index 3ca01be6e..cdc612090 100644
--- a/packages/core/src/repositories/commitsRepository/index.ts
+++ b/packages/core/src/repositories/commitsRepository/index.ts
@@ -13,7 +13,7 @@ import {
recomputeChanges,
RecomputedChanges,
} from '../../services/documents/recomputeChanges'
-import Repository, { PaginationArgs } from '../repository'
+import Repository from '../repository'
import { buildCommitsScope, columnSelection } from './utils/buildCommitsScope'
import { getHeadCommitForProject } from './utils/getHeadCommit'
@@ -129,17 +129,18 @@ export class CommitsRepository extends Repository<
return Result.ok(result[0]!)
}
- async getCommitsByProject({
+ getCommitsByProjectQuery({
project,
- page = 1,
filterByStatus = CommitStatus.All,
- pageSize = 20,
- }: { project: Project; filterByStatus?: CommitStatus } & PaginationArgs) {
+ }: {
+ project: Project
+ filterByStatus?: CommitStatus
+ }) {
const filter = filterByStatusQuery({
scope: this.scope,
status: filterByStatus,
})
- const query = this.db
+ return this.db
.select({
id: this.scope.id,
uuid: this.scope.uuid,
@@ -155,14 +156,6 @@ export class CommitsRepository extends Repository<
.from(this.scope)
.where(and(eq(this.scope.projectId, project.id), filter))
.orderBy(desc(this.scope.createdAt))
-
- const [rows] = await Repository.paginateQuery({
- query: query.$dynamic(),
- page,
- pageSize,
- })
-
- return Result.ok(rows)
}
async getChanges(id: number, tx = database) {
diff --git a/packages/core/src/repositories/repository.ts b/packages/core/src/repositories/repository.ts
index beaec22f0..cc821984a 100644
--- a/packages/core/src/repositories/repository.ts
+++ b/packages/core/src/repositories/repository.ts
@@ -1,17 +1,14 @@
-import { ColumnsSelection, eq, sql } from 'drizzle-orm'
-import { PgSelect, SubqueryWithSelection } from 'drizzle-orm/pg-core'
+import { ColumnsSelection, eq } from 'drizzle-orm'
+import { SubqueryWithSelection } from 'drizzle-orm/pg-core'
import { database } from '../client'
import { NotFoundError, Result } from '../lib'
-export type PaginationArgs = { page?: number; pageSize?: number }
export type QueryOptions = {
limit?: number
offset?: number
}
-type PaginatatedResult = [rows: Awaited, count: number]
-
export default abstract class Repository<
U extends ColumnsSelection,
T extends Record,
@@ -24,28 +21,6 @@ export default abstract class Repository<
this.db = db
}
- /**
- * This use $dynamic() query
- * https://orm.drizzle.team/docs/dynamic-query-building
- */
- static async paginateQuery({
- query,
- page = 1,
- pageSize = 20,
- }: {
- query: T
- } & PaginationArgs): Promise> {
- // @ts-ignore
- query.config.fields = {
- // @ts-ignore
- ...query.config.fields,
- __count: sql`count(*) over()`,
- }
- const rows = await query.limit(pageSize).offset((page - 1) * pageSize)
- const count = rows[0]?.__count ? Number(rows[0]?.__count) : 0
- return [rows, count]
- }
-
abstract get scope(): SubqueryWithSelection
async findAll(opts: QueryOptions = {}) {
diff --git a/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.test.ts b/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.test.ts
index 5f67c623b..ff54b1652 100644
--- a/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.test.ts
+++ b/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.test.ts
@@ -3,7 +3,7 @@ import { describe, expect, it } from 'vitest'
import { mergeCommit } from '../../services/commits'
import { updateDocument } from '../../services/documents'
import * as factories from '../../tests/factories'
-import { computeDocumentLogsWithMetadata } from './computeDocumentLogsWithMetadata'
+import { computeDocumentLogsWithMetadataQuery } from './computeDocumentLogsWithMetadata'
describe('getDocumentLogsWithMetadata', () => {
it('return all logs from merged commits', async () => {
@@ -39,11 +39,10 @@ describe('getDocumentLogsWithMetadata', () => {
commit: commit2,
})
- const [result] = await computeDocumentLogsWithMetadata({
+ const result = await computeDocumentLogsWithMetadataQuery({
workspaceId: project.workspaceId,
documentUuid: doc.documentUuid,
draft: commit2,
- pagination: { page: 1, pageSize: 100 },
})
expect(result.find((l) => l.uuid === log1.uuid)).toBeDefined()
@@ -98,11 +97,10 @@ describe('getDocumentLogsWithMetadata', () => {
commit: draft,
})
- const [result] = await computeDocumentLogsWithMetadata({
+ const result = await computeDocumentLogsWithMetadataQuery({
workspaceId: project.workspaceId,
documentUuid: doc.documentUuid,
draft,
- pagination: { page: 1, pageSize: 100 },
})
expect(result.find((l) => l.uuid === log1.uuid)).toBeDefined()
@@ -156,11 +154,10 @@ describe('getDocumentLogsWithMetadata', () => {
commit: draft2,
})
- const [result] = await computeDocumentLogsWithMetadata({
+ const result = await computeDocumentLogsWithMetadataQuery({
workspaceId: project.workspaceId,
documentUuid: doc.documentUuid,
draft: draft1,
- pagination: { page: 1, pageSize: 100 },
})
expect(result.find((l) => l.uuid === log1.uuid)).toBeDefined()
@@ -186,11 +183,10 @@ describe('getDocumentLogsWithMetadata', () => {
commit,
})
- const [result] = await computeDocumentLogsWithMetadata({
+ const result = await computeDocumentLogsWithMetadataQuery({
workspaceId: project.workspaceId,
documentUuid: doc.documentUuid,
draft: commit,
- pagination: { page: 1, pageSize: 100 },
})
expect(result.find((l) => l.uuid === log.uuid)).toBeDefined()
diff --git a/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.ts b/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.ts
index 84c3aa0c0..271b76b28 100644
--- a/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.ts
+++ b/packages/core/src/services/documentLogs/computeDocumentLogsWithMetadata.ts
@@ -2,30 +2,25 @@ import { and, desc, eq } from 'drizzle-orm'
import { Commit } from '../../browser'
import { database } from '../../client'
-import Repository, { PaginationArgs } from '../../repositories/repository'
import {
createDocumentLogQuery,
getCommitFilter,
} from './_createDocumentLogQuery'
-export async function computeDocumentLogsWithMetadata(
+export function computeDocumentLogsWithMetadataQuery(
{
workspaceId,
documentUuid,
draft,
- pagination,
}: {
workspaceId: number
documentUuid: string
draft?: Commit
- pagination: PaginationArgs
},
db = database,
) {
const { scope, baseQuery } = createDocumentLogQuery(workspaceId, db)
- const query = baseQuery
+ return baseQuery
.where(and(eq(scope.documentUuid, documentUuid), getCommitFilter(draft)))
.orderBy(desc(scope.createdAt))
-
- return Repository.paginateQuery({ query: query.$dynamic(), ...pagination })
}
diff --git a/packages/core/src/services/evaluationResults/computeEvaluationResultsWithMetadata.ts b/packages/core/src/services/evaluationResults/computeEvaluationResultsWithMetadata.ts
index f568c669e..005c7d0ac 100644
--- a/packages/core/src/services/evaluationResults/computeEvaluationResultsWithMetadata.ts
+++ b/packages/core/src/services/evaluationResults/computeEvaluationResultsWithMetadata.ts
@@ -2,32 +2,28 @@ import { and, desc, eq } from 'drizzle-orm'
import { Commit, Evaluation } from '../../browser'
import { database } from '../../client'
-import { Result, TypedResult } from '../../lib'
-import { EvaluationResultWithMetadata } from '../../repositories/evaluationResultsRepository'
import {
createEvaluationResultQuery,
getCommitFilter,
} from './_createEvaluationResultQuery'
-export async function computeEvaluationResultsWithMetadata(
+export function computeEvaluationResultsWithMetadataQuery(
{
workspaceId,
evaluation,
documentUuid,
draft,
- limit,
}: {
workspaceId: number
evaluation: Evaluation
documentUuid: string
draft?: Commit
- limit?: number
},
db = database,
-): Promise> {
+) {
const { evaluationResultsScope, documentLogsScope, baseQuery } =
createEvaluationResultQuery(workspaceId, db)
- const query = baseQuery
+ return baseQuery
.where(
and(
eq(evaluationResultsScope.evaluationId, evaluation.id),
@@ -36,8 +32,4 @@ export async function computeEvaluationResultsWithMetadata(
),
)
.orderBy(desc(evaluationResultsScope.createdAt))
-
- const result = await (limit ? query.limit(limit) : query)
-
- return Result.ok(result)
}
diff --git a/packages/core/src/websockets/constants.ts b/packages/core/src/websockets/constants.ts
index d8dd71cbc..51bed14b9 100644
--- a/packages/core/src/websockets/constants.ts
+++ b/packages/core/src/websockets/constants.ts
@@ -38,7 +38,7 @@ type EvaluationStatusArgs = {
enqueued: number
}
-type evaluationResultCreatedArgs = {
+type EvaluationResultCreatedArgs = {
workspaceId: number
evaluationId: number
documentUuid: string
@@ -55,7 +55,7 @@ type DocumentLogCreatedArgs = {
export type WebServerToClientEvents = {
evaluationStatus: (args: EvaluationStatusArgs) => void
- evaluationResultCreated: (args: evaluationResultCreatedArgs) => void
+ evaluationResultCreated: (args: EvaluationResultCreatedArgs) => void
joinWorkspace: (args: { workspaceId: number; userId: string }) => void
documentLogCreated: (args: DocumentLogCreatedArgs) => void
}
@@ -71,7 +71,7 @@ export type WorkersClientToServerEvents = {
}) => void
evaluationResultCreated: (args: {
workspaceId: number
- data: evaluationResultCreatedArgs
+ data: EvaluationResultCreatedArgs
}) => void
documentLogCreated: (args: {
workspaceId: number
diff --git a/packages/web-ui/src/ds/atoms/Input/index.tsx b/packages/web-ui/src/ds/atoms/Input/index.tsx
index c2b0901f5..47299812d 100644
--- a/packages/web-ui/src/ds/atoms/Input/index.tsx
+++ b/packages/web-ui/src/ds/atoms/Input/index.tsx
@@ -31,9 +31,21 @@ const inputVariants = cva(cn(INPUT_BASE_CLASSES), {
export type InputProps = Omit, 'size'> &
VariantProps &
- Omit
+ Omit & {
+ hideNativeAppearance?: boolean
+ }
const Input = forwardRef(function Input(
- { className, label, errors, errorStyle, description, type, size, ...props },
+ {
+ className,
+ label,
+ errors,
+ errorStyle,
+ description,
+ type,
+ size,
+ hideNativeAppearance = false,
+ ...props
+ },
ref,
) {
const inputComp = (
@@ -43,6 +55,7 @@ const Input = forwardRef(function Input(
className={cn(inputVariants({ size }), className, {
'border-red-500 focus-visible:ring-red-500': errors,
hidden: !!props.hidden,
+ 'appearance-none': hideNativeAppearance,
})}
{...props}
/>
diff --git a/packages/web-ui/src/ds/atoms/SplitPane/index.tsx b/packages/web-ui/src/ds/atoms/SplitPane/index.tsx
index f9e259a13..e00416973 100644
--- a/packages/web-ui/src/ds/atoms/SplitPane/index.tsx
+++ b/packages/web-ui/src/ds/atoms/SplitPane/index.tsx
@@ -14,7 +14,7 @@ import { ResizableBox, ResizeCallbackData, ResizeHandle } from 'react-resizable'
function Pane({ children }: { children: ReactNode }) {
return (
-
{children}
+
{children}
)
}
diff --git a/packages/web-ui/src/ds/atoms/Table/index.tsx b/packages/web-ui/src/ds/atoms/Table/index.tsx
index 77152cc36..d07a0e812 100644
--- a/packages/web-ui/src/ds/atoms/Table/index.tsx
+++ b/packages/web-ui/src/ds/atoms/Table/index.tsx
@@ -9,13 +9,16 @@ import { cn } from '../../../lib/utils'
import Text from '../Text'
type TableProps = HTMLAttributes & {
- maxHeight?: number
+ maxHeight?: number | string
}
const Table = forwardRef(
({ className, maxHeight, ...props }, ref) => (
@@ -49,19 +52,24 @@ const TableBody = forwardRef<
))
TableBody.displayName = 'TableBody'
-const TableFooter = forwardRef<
- HTMLTableSectionElement,
- HTMLAttributes
->(({ className, ...props }, ref) => (
- tr]:last:border-b-0',
- className,
- )}
- {...props}
- />
-))
+type TableFooterProps = HTMLAttributes & {
+ sticky?: boolean
+}
+const TableFooter = forwardRef(
+ ({ className, sticky = false, ...props }, ref) => (
+ tr]:last:border-b-0',
+ className,
+ {
+ 'sticky bottom-0': sticky,
+ },
+ )}
+ {...props}
+ />
+ ),
+)
TableFooter.displayName = 'TableFooter'
const TableRow = forwardRef<
diff --git a/packages/web-ui/src/ds/molecules/Chat/MessageList/index.tsx b/packages/web-ui/src/ds/molecules/Chat/MessageList/index.tsx
index c44699c6f..3a9136f18 100644
--- a/packages/web-ui/src/ds/molecules/Chat/MessageList/index.tsx
+++ b/packages/web-ui/src/ds/molecules/Chat/MessageList/index.tsx
@@ -1,10 +1,9 @@
'use client'
-import { Fragment, useState } from 'react'
+import { Fragment } from 'react'
import { Message as ConversationMessage } from '@latitude-data/compiler'
-import { Button } from '../../../atoms'
import { Message, MessageProps } from '../Message'
export function MessageList({
@@ -12,46 +11,17 @@ export function MessageList({
variant,
messageLayout,
separator = false,
- collapsable = false,
size,
}: {
messages: ConversationMessage[]
variant?: MessageProps['variant']
messageLayout?: MessageProps['layout']
- collapsable?: boolean
size?: MessageProps['size']
separator?: boolean
}) {
- const [isCollapsed, setIsCollapsed] = useState(
- collapsable && messages.length > 1,
- )
-
- const visibleMessages = isCollapsed ? messages.slice(-1) : messages
- const hiddenMessagesCount = messages.length - visibleMessages.length
-
return (
- {isCollapsed && messages.length > 1 && (
-
-
-
-
-
-
-
-
-
- )}
- {visibleMessages.map((message, index) => (
+ {messages.map((message, index) => (
{separator && index > 0 && (
@@ -65,13 +35,6 @@ export function MessageList({
/>
))}
- {!isCollapsed && collapsable && messages.length > 1 && (
-
-
-
- )}
)
}
diff --git a/packages/web-ui/src/ds/molecules/Pagination/index.tsx b/packages/web-ui/src/ds/molecules/Pagination/index.tsx
deleted file mode 100644
index de07d822e..000000000
--- a/packages/web-ui/src/ds/molecules/Pagination/index.tsx
+++ /dev/null
@@ -1,115 +0,0 @@
-import { ComponentProps, forwardRef } from 'react'
-import { ChevronLeft, ChevronRight, MoreHorizontal } from 'lucide-react'
-
-import { cn } from '../../../lib/utils'
-import { ButtonProps, buttonVariants } from '../../atoms/Button'
-
-const Pagination = ({ className, ...props }: ComponentProps<'nav'>) => (
-
-)
-Pagination.displayName = 'Pagination'
-
-const PaginationContent = forwardRef>(
- ({ className, ...props }, ref) => (
-
- ),
-)
-PaginationContent.displayName = 'PaginationContent'
-
-const PaginationItem = forwardRef>(
- ({ className, ...props }, ref) => (
-
- ),
-)
-PaginationItem.displayName = 'PaginationItem'
-
-type PaginationLinkProps = {
- isActive?: boolean
-} & Pick &
- ComponentProps<'a'>
-
-const PaginationLink = ({
- className,
- isActive,
- size = 'icon',
- ...props
-}: PaginationLinkProps) => (
-
-)
-PaginationLink.displayName = 'PaginationLink'
-
-const PaginationPrevious = ({
- className,
- ...props
-}: ComponentProps) => (
-
-
- Previous
-
-)
-PaginationPrevious.displayName = 'PaginationPrevious'
-
-const PaginationNext = ({
- className,
- ...props
-}: ComponentProps) => (
-
- Next
-
-
-)
-PaginationNext.displayName = 'PaginationNext'
-
-const PaginationEllipsis = ({
- className,
- ...props
-}: ComponentProps<'span'>) => (
-
-
- More pages
-
-)
-PaginationEllipsis.displayName = 'PaginationEllipsis'
-
-export {
- Pagination,
- PaginationContent,
- PaginationEllipsis,
- PaginationItem,
- PaginationLink,
- PaginationNext,
- PaginationPrevious,
-}
diff --git a/packages/web-ui/src/ds/molecules/index.ts b/packages/web-ui/src/ds/molecules/index.ts
index 8352d95a4..0d4781183 100644
--- a/packages/web-ui/src/ds/molecules/index.ts
+++ b/packages/web-ui/src/ds/molecules/index.ts
@@ -13,5 +13,4 @@ export * from './SelectableCard'
export * from './RangeBadge'
export * from './Charts'
export * from './EditableText'
-export * from './Pagination'
export * from './BlankSlateWithSteps'