Skip to content

Commit

Permalink
feature: create projects with draft commit (#201)
Browse files Browse the repository at this point in the history
  • Loading branch information
geclos authored Sep 17, 2024
1 parent efaa130 commit 0ccb20f
Show file tree
Hide file tree
Showing 16 changed files with 91 additions and 62 deletions.
11 changes: 11 additions & 0 deletions apps/web/src/app/(private)/_data-access/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ export const findCommitCached = cache(
},
)

export const findCommitsByProjectCached = cache(
async ({ projectId }: { projectId: number }) => {
const { workspace } = await getCurrentUser()
const commitsScope = new CommitsRepository(workspace.id)
const result = await commitsScope.filterByProject(projectId)
const commits = result.unwrap()

return commits
},
)

export const getDocumentByUuidCached = cache(
async ({
projectId,
Expand Down
14 changes: 7 additions & 7 deletions apps/web/src/app/(private)/projects/[projectId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { HEAD_COMMIT, type Project } from '@latitude-data/core/browser'
import { NotFoundError } from '@latitude-data/core/lib/errors'
import {
findCommitCached,
findCommitsByProjectCached,
findProjectCached,
} from '$/app/(private)/_data-access'
import { lastSeenCommitCookieName } from '$/helpers/cookies/lastSeenCommit'
Expand Down Expand Up @@ -36,21 +36,21 @@ export default async function ProjectPage({ params }: ProjectPageParams) {
if (!lastSeenCommitUuid || lastSeenCommitUuid?.value === HEAD_COMMIT) {
url = PROJECT_ROUTE({ id: +project.id }).commits.latest
} else {
const commitUuid = await findCommitCached({
uuid: lastSeenCommitUuid.value,
projectId: Number(params.projectId),
const commits = await findCommitsByProjectCached({
projectId: project.id,
})
.then((c) => c.uuid)
.catch(() => HEAD_COMMIT) // Reditect to HEAD COMMIT if the commit does not exist
const commit = commits.filter((c) => !!c.mergedAt)[0] || commits[0]
if (!commit) throw new NotFoundError('No commits found')

url = PROJECT_ROUTE({ id: +project.id }).commits.detail({
uuid: commitUuid,
uuid: commit.uuid,
}).root
}
} catch (error) {
if (error instanceof NotFoundError) {
return notFound()
}

throw error
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export default async function DocumentsLayout({
const resizableId = ResizableGroups.DocumentSidebar
const sidebarWidth =
getResizablePanelGroupData({ group: resizableId }) ?? MIN_SIDEBAR_WIDTH_PX

return (
<DocumentDetailWrapper
resizableId={resizableId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { useCallback, useState } from 'react'

import { Commit, HEAD_COMMIT } from '@latitude-data/core/browser'
import { HEAD_COMMIT } from '@latitude-data/core/browser'
import {
FilesTree,
useCurrentCommit,
Expand All @@ -21,7 +21,6 @@ export default function ClientFilesTree({
documents: serverDocuments,
currentDocument,
}: {
headCommit: Commit
documents: SidebarDocument[]
currentDocument: SidebarDocument | undefined
}) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,20 +110,22 @@ function CommitItem({
onCommitPublish,
onCommitDelete,
}: {
commit: Commit
commit?: Commit
currentDocument?: DocumentVersion
headCommitId: number
user: SimpleUser | undefined
headCommitId?: number
user?: SimpleUser
onCommitPublish: ReactStateDispatch<number | null>
onCommitDelete: ReactStateDispatch<number | null>
}) {
const isHead = commit.id === headCommitId
const isDraft = !commit.mergedAt
const { project } = useCurrentProject()
const router = useNavigate()
const selectedSegment = useSelectedLayoutSegment()
if (!commit) return null

const isHead = commit.id === headCommitId
const isDraft = !commit.mergedAt
const badgeType =
commit.id === headCommitId ? BadgeType.Head : BadgeType.Draft
const selectedSegment = useSelectedLayoutSegment()

const commitPath = useMemo(() => {
const commitRoute = ROUTES.projects
Expand Down Expand Up @@ -186,7 +188,7 @@ export default function CommitSelector({
currentDocument,
draftCommits,
}: {
headCommit: Commit
headCommit?: Commit | undefined
currentCommit: Commit
currentDocument?: DocumentVersion
draftCommits: Commit[]
Expand All @@ -212,17 +214,17 @@ export default function CommitSelector({
commit,
title: commit.title ?? commit.uuid,
badgeType:
currentCommit?.id === headCommit.id
currentCommit?.id === headCommit?.id
? BadgeType.Head
: foundCommit
? BadgeType.Draft
: BadgeType.Merged,
}
}, [commits, currentCommit.id, headCommit.id])
}, [commits, currentCommit.id, headCommit?.id])
const [publishCommit, setPublishCommit] = useState<number | null>(null)
const [deleteCommit, setDeleteCommit] = useState<number | null>(null)
const canPublish = currentCommit.id !== headCommit.id
const isHead = currentCommit.id === headCommit.id
const canPublish = currentCommit.id !== headCommit?.id
const isHead = currentCommit.id === headCommit?.id
return (
<div className='flex flex-col gap-y-2'>
<SelectRoot value={String(currentCommit.id)}>
Expand All @@ -244,8 +246,8 @@ export default function CommitSelector({
<CommitItem
commit={headCommit}
currentDocument={currentDocument}
headCommitId={headCommit.id}
user={usersById[headCommit.userId]}
headCommitId={headCommit?.id}
user={headCommit ? usersById[headCommit?.userId] : undefined}
onCommitPublish={setPublishCommit}
onCommitDelete={setDeleteCommit}
/>
Expand All @@ -254,7 +256,7 @@ export default function CommitSelector({
<CommitItem
commit={commit}
currentDocument={currentDocument}
headCommitId={headCommit.id}
headCommitId={headCommit?.id}
user={usersById[commit.userId]}
onCommitPublish={setPublishCommit}
onCommitDelete={setDeleteCommit}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,8 @@ export default async function Sidebar({
status: CommitStatus.Draft,
})
const commitsScope = new CommitsRepository(workspace.id)
const headCommit = await commitsScope
.getHeadCommit(project.id)
.then((r) => r.unwrap())
const headCommitResult = await commitsScope.getHeadCommit(project.id)
const headCommit = headCommitResult.value

if (fetchCommitsError) {
throw fetchCommitsError
Expand All @@ -50,7 +49,6 @@ export default async function Sidebar({
tree={
<ClientFilesTree
currentDocument={currentDocument}
headCommit={headCommit}
documents={documents}
/>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ export default async function DocumentPage({
params: { projectId: string; commitUuid: string; documentUuid: string }
}) {
const projectId = Number(params.projectId)
const commintUuid = params.commitUuid
const commit = await findCommitCached({ projectId, uuid: commintUuid })
const commitUuid = params.commitUuid
const commit = await findCommitCached({ projectId, uuid: commitUuid })
const logs = await getDocumentLogsWithMetadataCached({
documentUuid: params.documentUuid,
commit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import {
type Project,
} from '@latitude-data/core/browser'
import { NotFoundError } from '@latitude-data/core/lib/errors'
import {
CommitsRepository,
ProjectsRepository,
} from '@latitude-data/core/repositories/index'
import { CommitProvider, ProjectProvider } from '@latitude-data/web-ui'
import { BreadcrumpBadge } from '@latitude-data/web-ui/browser'
import {
findCommitsByProjectCached,
findProjectCached,
} from '$/app/(private)/_data-access'
import { NAV_LINKS } from '$/app/(private)/_lib/constants'
import { ProjectPageParams } from '$/app/(private)/projects/[projectId]/page'
import BreadcrumpLink from '$/components/BreadcrumpLink'
Expand All @@ -34,23 +34,25 @@ export default async function CommitLayout({
children,
params,
}: CommitPageParams) {
const isHead = params.commitUuid === HEAD_COMMIT
let session: SessionData
let project: Project
let commit: Commit
let commit: Commit | undefined
let isHead = false
try {
session = await getCurrentUser()
const projectsRepo = new ProjectsRepository(session.workspace.id)
const commitsRepo = new CommitsRepository(session.workspace.id)
project = (
await projectsRepo.getProjectById(Number(params.projectId))
).unwrap()
commit = (
await commitsRepo.getCommitByUuid({
uuid: params.commitUuid,
projectId: Number(params.projectId),
})
).unwrap()
project = await findProjectCached({
projectId: Number(params.projectId),
workspaceId: session.workspace.id,
})
const commits = await findCommitsByProjectCached({ projectId: project.id })
if (params.commitUuid === HEAD_COMMIT) {
commit = commits.find((c) => !!c.mergedAt)
} else {
commit = commits.find((c) => c.uuid === params.commitUuid)
}

if (!commit) throw new NotFoundError('Commit not found')
isHead = commit.uuid === HEAD_COMMIT
} catch (error) {
if (error instanceof NotFoundError) return notFound()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ describe('Commits by project', () => {
filterByStatus: CommitStatus.Draft,
})
.then((r) => r.unwrap())

expect(list).toHaveLength(8)
})

Expand Down
19 changes: 18 additions & 1 deletion packages/core/src/repositories/commitsRepository/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,14 @@ export class CommitsRepository extends Repository<
return Result.error(new NotFoundError('Project ID is required'))
}

return this.getHeadCommit(projectId)
const headCommit = await this.getHeadCommit(projectId).then((r) =>
r.unwrap(),
)
if (!headCommit) {
return Result.error(new NotFoundError('Head commit not found'))
}

return Result.ok(headCommit)
}

const result = await this.db
Expand Down Expand Up @@ -194,4 +201,14 @@ export class CommitsRepository extends Repository<
}),
)
}

async filterByProject(projectId: number) {
const result = await this.db
.select()
.from(this.scope)
.where(eq(this.scope.projectId, projectId))
.orderBy(desc(this.scope.mergedAt))

return Result.ok(result)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { and, desc, eq, isNotNull } from 'drizzle-orm'

import { database } from '../../../client'
import { InferedReturnType, NotFoundError, Result } from '../../../lib'
import { InferedReturnType, Result } from '../../../lib'
import { buildCommitsScope } from './buildCommitsScope'

export async function getHeadCommitForProject(
Expand All @@ -26,9 +26,5 @@ export async function getHeadCommitForProject(
.orderBy(desc(commitsScope.mergedAt))
.limit(1)

if (result.length < 1) {
return Result.error(new NotFoundError('No head commit found'))
}

return Result.ok(result[0]!)
return Result.ok(result[0])
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export class DocumentVersionsRepository extends Repository<
/**
* NOTE: By default we don't include deleted documents
*/
async getDocumentsAtCommit(commit: Commit) {
async getDocumentsAtCommit(commit?: Commit) {
const result = await this.getAllDocumentsAtCommit({ commit })
if (result.error) return result

Expand Down Expand Up @@ -179,7 +179,9 @@ export class DocumentVersionsRepository extends Repository<
return Result.ok(changedDocuments)
}

private async getAllDocumentsAtCommit({ commit }: { commit: Commit }) {
private async getAllDocumentsAtCommit({ commit }: { commit?: Commit }) {
if (!commit) return Result.ok([])

const documentsFromMergedCommits = await this.getDocumentsFromMergedCommits(
{
projectId: commit.projectId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,10 @@ async function getDocumentsAtCommit(
if (projectResult.error) return projectResult

const commitsScope = buildCommitsScope(workspaceId, tx)
const headCommitResult = await getHeadCommitForProject(
const headCommit = await getHeadCommitForProject(
{ projectId: projectResult.value.id, commitsScope },
tx,
)
if (headCommitResult.error) return headCommitResult

const headCommit = headCommitResult.value
).then((r) => r.unwrap())

const docsScope = new DocumentVersionsRepository(workspaceId, tx)
const headDocumentsResult = await docsScope.getDocumentsAtCommit(headCommit)
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/services/documents/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ describe('updateDocument', () => {
const fooDoc = documents.find((d) => d.path === 'foo')!

const result = await updateDocument({
commit,
commit: commit!,
document: fooDoc,
content: 'bar',
})
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/services/projects/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ export async function createProject(
workspace,
user,
name,
mergedAt,
}: {
name: string
workspace: Workspace
user: User
mergedAt?: Date
},
db = database,
) {
Expand All @@ -27,8 +29,8 @@ export async function createProject(
const result = await createCommit({
data: {
title: 'Initial version',
mergedAt: new Date(),
version: 0,
mergedAt,
},
project,
user,
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/tests/factories/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export async function createProject(projectData: Partial<ICreateProject> = {}) {
name: name ?? randomName,
workspace,
user,
mergedAt: new Date(),
})
const project = result.unwrap()
const commitsScope = new CommitsRepository(workspace.id)
Expand Down

0 comments on commit 0ccb20f

Please sign in to comment.