From 952ebfdf9b0e0ce20793d5f5236f445b9e6fd340 Mon Sep 17 00:00:00 2001 From: Ahmet Kilinc Date: Fri, 25 Jul 2025 11:27:06 +0100 Subject: [PATCH 1/5] refactor: update project card link and remove unused markdown components - Updated the project card link to dynamically generate based on the git host (GitHub or GitLab). - Removed unused markdown content, project description, and project page components to streamline the codebase. - Added a new API endpoint to fetch project details by repository for better integration. --- .../[org]/[repo]}/markdown-content.tsx | 0 .../[provider]/[org]/[repo]/page.tsx | 13 + .../[org]/[repo]}/project-description.tsx | 12 +- .../[org]/[repo]}/project-page.tsx | 256 ++++++++++++------ .../(projects)/projects/[id]/page.tsx | 7 - .../(projects)/projects/project-card.tsx | 43 +-- packages/api/src/routers/projects.ts | 29 ++ 7 files changed, 247 insertions(+), 113 deletions(-) rename apps/web/app/(public)/(projects)/{projects/[id] => [provider]/[org]/[repo]}/markdown-content.tsx (100%) create mode 100644 apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx rename apps/web/app/(public)/(projects)/{projects/[id] => [provider]/[org]/[repo]}/project-description.tsx (96%) rename apps/web/app/(public)/(projects)/{projects/[id] => [provider]/[org]/[repo]}/project-page.tsx (85%) delete mode 100644 apps/web/app/(public)/(projects)/projects/[id]/page.tsx diff --git a/apps/web/app/(public)/(projects)/projects/[id]/markdown-content.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/markdown-content.tsx similarity index 100% rename from apps/web/app/(public)/(projects)/projects/[id]/markdown-content.tsx rename to apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/markdown-content.tsx diff --git a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx new file mode 100644 index 00000000..4f8cdfa8 --- /dev/null +++ b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx @@ -0,0 +1,13 @@ +import ProjectPage from './project-page'; + +export default async function Page({ + params, +}: { + params: Promise<{ provider: string; org: string; repo: string }>; +}) { + const { provider, org, repo } = await params; + + console.log(provider, org, repo); + + return ; +} diff --git a/apps/web/app/(public)/(projects)/projects/[id]/project-description.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx similarity index 96% rename from apps/web/app/(public)/(projects)/projects/[id]/project-description.tsx rename to apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx index d41eb749..a8595227 100644 --- a/apps/web/app/(public)/(projects)/projects/[id]/project-description.tsx +++ b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx @@ -13,10 +13,12 @@ export default function ProjectDescription({ repo, project, isOwner, + isNotInDatabase, }: { repo: ProjectData; project: ProjectWithRelations; isOwner: boolean; + isNotInDatabase: boolean; }) { const getAvatarImage = (): string => { if (repo && repo.owner && typeof repo.owner.avatar_url === 'string') { @@ -41,12 +43,14 @@ export default function ProjectDescription({ repoOwnerName={repo?.owner?.name || repo?.namespace?.name || ''} className="h-12 w-12 flex-shrink-0 rounded-none md:h-16 md:w-16" /> +
- + {!isNotInDatabase && }
@@ -110,17 +114,19 @@ function StatusBadges({ project }: { project: ProjectWithRelations }) { function ProjectTitleAndTicks({ project, className, + isNotInDatabase, }: { project: ProjectWithRelations; className: string; + isNotInDatabase: boolean; }) { return (

{project?.name}

- + {!isNotInDatabase && }
- + {!isNotInDatabase && }
); } diff --git a/apps/web/app/(public)/(projects)/projects/[id]/project-page.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-page.tsx similarity index 85% rename from apps/web/app/(public)/(projects)/projects/[id]/project-page.tsx rename to apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-page.tsx index b296b076..2e710b12 100644 --- a/apps/web/app/(public)/(projects)/projects/[id]/project-page.tsx +++ b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-page.tsx @@ -21,12 +21,12 @@ import { import { Tabs, TabsContent, TabsList, TabsTrigger } from '@workspace/ui/components/tabs'; import { ClaimProjectDialog } from '@/components/project/claim-project-dialog'; import { ContributorData, ProjectWithRelations } from '@workspace/api'; +import ProjectErrorPage from '../../../projects/project-error-page'; import { Separator } from '@workspace/ui/components/separator'; import { useQueries, useQuery } from '@tanstack/react-query'; import { projectProviderEnum } from '@workspace/db/schema'; import LoadingSpinner from '@/components/loading-spinner'; import ProjectDescription from './project-description'; -import ProjectErrorPage from '../project-error-page'; import { MarkdownContent } from './markdown-content'; import { authClient } from '@workspace/auth/client'; import { useEffect, useState, useRef } from 'react'; @@ -155,19 +155,35 @@ const isValidProvider = ( return provider === 'github' || provider === 'gitlab'; }; -function useProject(id: string) { +function useProject(provider: string, org: string, repo: string) { const trpc = useTRPC(); - const query = useQuery(trpc.projects.getProject.queryOptions({ id }, { retry: false })); + const query = useQuery( + trpc.projects.getProjectByRepo.queryOptions({ provider, org, repo }, { retry: false }), + ); return { - project: query.data as ProjectWithRelations | undefined, + project: query.data as ProjectWithRelations | null | undefined, isLoading: query.isLoading, error: query.error, + isNotInDatabase: query.data === null, }; } -export default function ProjectPage({ id }: { id: string }) { - const { project, isLoading: projectLoading, error: projectError } = useProject(id); +export default function ProjectPage({ + provider, + org, + repoId, +}: { + provider: string; + org: string; + repoId: string; +}) { + const { + project, + isLoading: projectLoading, + error: projectError, + isNotInDatabase, + } = useProject(provider, org, repoId); const { data: session } = authClient.useSession(); const user = session?.user; const [showShadow, setShowShadow] = useState(false); @@ -183,7 +199,6 @@ export default function ProjectPage({ id }: { id: string }) { return () => window.removeEventListener('scroll', handleScroll); }, []); - // Scroll active tab into view on smaller screens useEffect(() => { if (tabsListRef.current) { const activeTabElement = tabsListRef.current.querySelector( @@ -209,14 +224,50 @@ export default function ProjectPage({ id }: { id: string }) { const trpc = useTRPC(); + const normalizedProvider = provider === 'gh' ? 'github' : provider === 'gl' ? 'gitlab' : provider; + const gitRepoUrl = `${org}/${repoId}`; + + const virtualProject = isNotInDatabase + ? { + id: `virtual-${normalizedProvider}-${org}-${repoId}`, + ownerId: null, + logoUrl: null, + gitRepoUrl: gitRepoUrl, + gitHost: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], + name: repoId, + description: null, + socialLinks: null, + approvalStatus: 'approved' as const, + isPinned: false, + hasBeenAcquired: false, + isLookingForContributors: false, + isLookingForInvestors: false, + isHiring: false, + isPublic: true, + isRepoPrivate: false, + acquiredBy: null, + createdAt: new Date(), + updatedAt: new Date(), + statusId: '', + typeId: '', + deletedAt: null, + status: undefined, + type: undefined, + tagRelations: [], + } + : project; + + console.dir(virtualProject, { depth: null }); + const repoQuery = useQuery( trpc.repository.getRepo.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, ), @@ -225,11 +276,14 @@ export default function ProjectPage({ id }: { id: string }) { const repoDataQuery = useQuery( trpc.repository.getRepoData.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!repoQuery.data && !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + !!repoQuery.data && + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + isValidProvider(normalizedProvider), retry: false, }, ), @@ -239,61 +293,79 @@ export default function ProjectPage({ id }: { id: string }) { queries: [ trpc.repository.getIssues.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!repoQuery.data && !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + !!repoQuery.data && + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + isValidProvider(normalizedProvider), retry: false, }, ), trpc.repository.getPullRequests.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!repoQuery.data && !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + !!repoQuery.data && + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + isValidProvider(normalizedProvider), retry: false, }, ), trpc.repository.getReadme.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!repoQuery.data && !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + !!repoQuery.data && + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + isValidProvider(normalizedProvider), retry: false, }, ), trpc.repository.getContributing.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!repoQuery.data && !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + !!repoQuery.data && + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + isValidProvider(normalizedProvider), retry: false, }, ), trpc.repository.getCodeOfConduct.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!repoQuery.data && !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + !!repoQuery.data && + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + isValidProvider(normalizedProvider), retry: false, }, ), - trpc.projects.getContributors.queryOptions( + trpc.repository.getContributors.queryOptions( { - url: project?.gitRepoUrl as string, - provider: project?.gitHost as (typeof projectProviderEnum.enumValues)[number], + url: gitRepoUrl, + provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: !!repoQuery.data && !!project?.gitRepoUrl && isValidProvider(project?.gitHost), + enabled: + !!repoQuery.data && + (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + isValidProvider(normalizedProvider), retry: false, }, ), @@ -308,11 +380,11 @@ export default function ProjectPage({ id }: { id: string }) { ); } - if (projectError || !project) { + if (projectError && !isNotInDatabase) { return ; } - if (!project.gitRepoUrl) { + if (!virtualProject?.gitRepoUrl) { return ; } @@ -328,14 +400,14 @@ export default function ProjectPage({ id }: { id: string }) { return repoQuery.refetch()} />; } - const isUnclaimed = !project.ownerId; - const isOwner = user?.id === project.ownerId; + const isUnclaimed = !virtualProject.ownerId; + const isOwner = user?.id === virtualProject.ownerId; const repoData = repoQuery.data as Repository; const repo = { ...repoData, id: repoData.html_url || repoData.web_url || '', - name: project.gitRepoUrl?.split('/').pop() || '', - url: repoData.html_url || repoData.web_url || project.gitRepoUrl || '', + name: virtualProject.gitRepoUrl?.split('/').pop() || '', + url: repoData.html_url || repoData.web_url || virtualProject.gitRepoUrl || '', }; const repoStats = repoDataQuery.data as RepoData | undefined; const issuesCount = repoStats?.issuesCount || 0; @@ -356,15 +428,26 @@ export default function ProjectPage({ id }: { id: string }) { />
- + {!isNotInDatabase ? ( + + ) : ( +
+

This repo has not yet been added to oss.now.

+
+ )}
- +
@@ -493,7 +576,7 @@ export default function ProjectPage({ id }: { id: string }) { @@ -550,17 +633,17 @@ export default function ProjectPage({ id }: { id: string }) { {issuesCount > 10 && ( View all {issuesCount} open issues on{' '} - {project?.gitHost === 'github' ? 'GitHub' : 'GitLab'} → + {virtualProject.gitHost === 'github' ? 'GitHub' : 'GitLab'} → )}
@@ -574,7 +657,7 @@ export default function ProjectPage({ id }: { id: string }) { {otherQueries[1].isLoading ? (
- +
) : pullRequests ? ( pullRequests.length === 0 ? ( @@ -621,7 +704,7 @@ export default function ProjectPage({ id }: { id: string }) { href={pr.html_url || pr.web_url || '#'} target="_blank" event="project_page_pull_request_link_clicked" - eventObject={{ projectId: project.id }} + eventObject={{ projectId: virtualProject.id }} className="mt-2 block text-sm font-medium text-neutral-300 transition-colors hover:text-white" > {pr.title} @@ -672,7 +755,7 @@ export default function ProjectPage({ id }: { id: string }) { @@ -684,17 +767,17 @@ export default function ProjectPage({ id }: { id: string }) { {pullRequestsCount > 10 && ( View all {pullRequestsCount} open pull requests on{' '} - {project?.gitHost === 'github' ? 'GitHub' : 'GitLab'} → + {virtualProject.gitHost === 'github' ? 'GitHub' : 'GitLab'} → )}
@@ -780,10 +863,13 @@ export default function ProjectPage({ id }: { id: string }) { = 500 @@ -902,7 +988,7 @@ export default function ProjectPage({ id }: { id: string }) {

About

- {project?.createdAt && ( + {virtualProject?.createdAt && (
Created @@ -910,7 +996,7 @@ export default function ProjectPage({ id }: { id: string }) {
)} - {project?.updatedAt && ( + {virtualProject?.updatedAt && (
Updated @@ -918,40 +1004,42 @@ export default function ProjectPage({ id }: { id: string }) {
)} - {project?.gitHost && ( + {virtualProject?.gitHost && (
Host - {project?.gitHost} + {virtualProject?.gitHost}
)}
Visibility - {project?.isPublic ? 'Public' : 'Private'} + {virtualProject?.isPublic ? 'Public' : 'Private'}
-
-

- - Tags -

-
- {project?.tagRelations?.map((relation, index: number) => ( - - {relation.tag?.displayName || relation.tag?.name} - - ))} + {!isNotInDatabase && ( +
+

+ + Tags +

+
+ {virtualProject?.tagRelations?.map((relation, index: number) => ( + + {relation.tag?.displayName || relation.tag?.name} + + ))} +
-
+ )} - {project?.hasBeenAcquired && project?.acquiredBy && ( + {virtualProject?.hasBeenAcquired && virtualProject?.acquiredBy && (
@@ -960,13 +1048,13 @@ export default function ProjectPage({ id }: { id: string }) {

This project has been acquired

)} - {(project?.isLookingForContributors || - project?.isLookingForInvestors || - project?.isHiring) && ( + {(virtualProject?.isLookingForContributors || + virtualProject?.isLookingForInvestors || + virtualProject?.isHiring) && (

Opportunities

- {project?.isLookingForContributors && ( + {virtualProject?.isLookingForContributors && (
@@ -977,7 +1065,7 @@ export default function ProjectPage({ id }: { id: string }) {
)} - {project?.isLookingForInvestors && ( + {virtualProject?.isLookingForInvestors && (
@@ -988,7 +1076,7 @@ export default function ProjectPage({ id }: { id: string }) {
)} - {project?.isHiring && ( + {virtualProject?.isHiring && (
diff --git a/apps/web/app/(public)/(projects)/projects/[id]/page.tsx b/apps/web/app/(public)/(projects)/projects/[id]/page.tsx deleted file mode 100644 index 9cac419f..00000000 --- a/apps/web/app/(public)/(projects)/projects/[id]/page.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import ProjectPage from './project-page'; - -export default async function Page({ params }: { params: Promise<{ id: string }> }) { - const { id } = await params; - - return ; -} diff --git a/apps/web/app/(public)/(projects)/projects/project-card.tsx b/apps/web/app/(public)/(projects)/projects/project-card.tsx index dce97e04..70a77103 100644 --- a/apps/web/app/(public)/(projects)/projects/project-card.tsx +++ b/apps/web/app/(public)/(projects)/projects/project-card.tsx @@ -27,9 +27,14 @@ export default function ProjectCard({ project }: { project: Project }) { if (isError) return
Error
; + const normalizedProvider = + project.gitHost === 'github' ? 'gh' : project.gitHost === 'gitlab' ? 'gl' : project.gitHost; + + const href = `/${normalizedProvider}/${project.gitRepoUrl}`; + return ( )}
-
-

- {project.name} -

- {(project.isLookingForContributors || project.hasBeenAcquired) && ( -
- {project.isLookingForContributors && ( - - Open to contributors - - )} - {project.hasBeenAcquired && ( - - Acquired - - )} -
- )} +
+

+ {project.name} +

+ {(project.isLookingForContributors || project.hasBeenAcquired) && ( +
+ {project.isLookingForContributors && ( + + Open to contributors + + )} + {project.hasBeenAcquired && ( + + Acquired + + )} +
+ )}

{project.description} diff --git a/packages/api/src/routers/projects.ts b/packages/api/src/routers/projects.ts index 7c85128a..0bb6fe9e 100644 --- a/packages/api/src/routers/projects.ts +++ b/packages/api/src/routers/projects.ts @@ -482,6 +482,35 @@ export const projectsRouter = createTRPCRouter({ }, }); }), + + getProjectByRepo: publicProcedure + .input(z.object({ provider: z.string(), org: z.string(), repo: z.string() })) + .query(async ({ ctx, input }) => { + let provider = input.provider; + if (provider === 'gh') { + provider = 'github'; + } else if (provider === 'gl') { + provider = 'gitlab'; + } + + const repo = await ctx.db.query.project.findFirst({ + where: and( + eq(project.gitHost, provider as (typeof projectProviderEnum.enumValues)[number]), + eq(project.gitRepoUrl, `${input.org}/${input.repo}`), + ), + with: { + status: true, + type: true, + tagRelations: { + with: { + tag: true, + }, + }, + }, + }); + + return repo || null; + }), addProject: protectedProcedure.input(createProjectInput).mutation(async ({ ctx, input }) => { const { statusId, typeId, tagIds } = await resolveAllIds(ctx.db, { status: input.status, From 1365735743d91ddf3024c631270a3a7234f6307e Mon Sep 17 00:00:00 2001 From: Ahmet Kilinc Date: Sat, 26 Jul 2025 02:02:11 +0100 Subject: [PATCH 2/5] remove comments --- .../[provider]/[org]/[repo]/page.tsx | 2 - .../[org]/[repo]/project-description.tsx | 2 + .../[provider]/[org]/[repo]/project-page.tsx | 2 - packages/api/src/driver/github.ts | 52 ++----------------- packages/api/src/driver/gitlab.ts | 16 ++---- 5 files changed, 10 insertions(+), 64 deletions(-) diff --git a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx index 4f8cdfa8..dcf74980 100644 --- a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx +++ b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/page.tsx @@ -7,7 +7,5 @@ export default async function Page({ }) { const { provider, org, repo } = await params; - console.log(provider, org, repo); - return ; } diff --git a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx index a8595227..5a26c85c 100644 --- a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx +++ b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx @@ -194,6 +194,8 @@ function ProjectDescriptionText({ project }: { project: ProjectWithRelations }) const isLong = description.length > CHAR_LIMIT; const displayText = expanded || !isLong ? description : description.slice(0, CHAR_LIMIT) + '...'; + console.log(description); + return (

0) { allContributors.push(...contributors); page++; if (contributors.length < 100) { - console.log( - `Reached end of contributors at page ${page - 1} (got ${contributors.length} contributors)`, - ); hasMore = false; } if (allContributors.length >= 1000) { - console.log( - `Early termination: reached ${allContributors.length} contributors via API`, - ); break; } } else { - console.log(`No contributors found on page ${page}, stopping`); hasMore = false; } } @@ -826,18 +792,11 @@ export class GithubManager implements GitManager { })) .slice(0, 500); - console.log( - `Successfully found ${allContributors.length} total contributors, returning ${contributorData.length} via contributors API`, - ); return contributorData; - } else { - console.log('Contributors API returned no results, falling back to PR analysis'); } } catch (contributorsApiError) { - console.log( - 'Contributors API failed, falling back to PR analysis:', - contributorsApiError, - ); + // TODO: handle error + console.error('Error fetching GitHub contributors:', contributorsApiError); } const contributorMap = new Map(); let page = 1; @@ -885,7 +844,6 @@ export class GithubManager implements GitManager { page++; if (contributorMap.size >= 500) { - console.log('Early termination: reached 500 contributors'); break; } } @@ -895,11 +853,9 @@ export class GithubManager implements GitManager { const limitedContributors = contributors.slice(0, 500); - console.log( - `Found ${limitedContributors.length} unique contributors from ${processedPRs} PRs`, - ); return limitedContributors; } catch (error) { + // TODO: handle error console.error('Error fetching GitHub contributors:', error); throw new TRPCError({ code: 'INTERNAL_SERVER_ERROR', diff --git a/packages/api/src/driver/gitlab.ts b/packages/api/src/driver/gitlab.ts index eb8b471e..168c5ab7 100644 --- a/packages/api/src/driver/gitlab.ts +++ b/packages/api/src/driver/gitlab.ts @@ -629,10 +629,6 @@ export class GitlabManager implements GitManager { isOwner = true; ownershipType = 'repository owner'; } else if (repoData.owner.type === 'Organization') { - console.log( - `Checking org ownership for ${currentUser.username} in org ${repoData.owner.login}`, - ); - try { const repoPermissions = await this.getRepoPermissions(identifier); @@ -659,19 +655,17 @@ export class GitlabManager implements GitManager { } } } catch (orgError) { - console.log('User is not a member of the group or group check failed:', orgError); + // TODO: handle error + console.error('Error checking GitLab group membership:', orgError); } } } catch (error) { - console.log( - 'User does not have collaborator access to the repository:', - error instanceof Error ? error.message : String(error), - ); + // TODO: handle error + console.error('Error checking GitLab repository permissions:', error); } } if (!isOwner) { - console.log(`Claim denied for user ${currentUser.username} on repo ${owner}/${repo}`); await ctx.db.insert(projectClaim).values({ projectId, userId: ctx.session!.userId, @@ -692,8 +686,6 @@ export class GitlabManager implements GitManager { }); } - console.log(`Claim approved: ${currentUser.username} is ${ownershipType} for ${owner}/${repo}`); - const updatedProject = await ctx.db .update(project) .set({ From 6bca7335b0b711819a290de9f7492bdae81f9745 Mon Sep 17 00:00:00 2001 From: Ahmet Kilinc Date: Sat, 26 Jul 2025 02:11:38 +0100 Subject: [PATCH 3/5] lots of cleanup --- .../[provider]/[org]/[repo]/project-page.tsx | 260 ++++++++++-------- 1 file changed, 140 insertions(+), 120 deletions(-) diff --git a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-page.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-page.tsx index 6a5a3c00..32f1bd4e 100644 --- a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-page.tsx +++ b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-page.tsx @@ -93,6 +93,17 @@ interface Repository { id?: string; name?: string; url?: string; + description?: string; + homepage?: string; + isPrivate?: boolean; + private?: boolean; + topics?: string[]; + owner?: { + avatar_url?: string; + }; + namespace?: { + avatar_url?: string; + }; } interface RepoData { @@ -101,53 +112,53 @@ interface RepoData { pullRequestsCount?: number; } -interface Project { - id: string; - ownerId: string | null; - logoUrl: string | null; - gitRepoUrl: string | null; - gitHost: string | null; - name: string; - description: string | null; - socialLinks: { - twitter?: string; - discord?: string; - linkedin?: string; - website?: string; - [key: string]: string | undefined; - } | null; - approvalStatus: 'pending' | 'approved' | 'rejected'; - isPinned: boolean; - hasBeenAcquired: boolean; - isLookingForContributors: boolean; - isLookingForInvestors: boolean; - isHiring: boolean; - isPublic: boolean; - isRepoPrivate: boolean; - acquiredBy: string | null; - createdAt: Date; - updatedAt: Date; - statusId: string; - typeId: string; - deletedAt: Date | null; - status?: { - id: string; - name: string; - displayName?: string; - }; - type?: { - id: string; - name: string; - displayName?: string; - }; - tagRelations?: Array<{ - tag?: { - id?: string; - name: string; - displayName?: string; - }; - }>; -} +// interface Project { +// id: string; +// ownerId: string | null; +// logoUrl: string | null; +// gitRepoUrl: string | null; +// gitHost: string | null; +// name: string; +// description: string | null; +// socialLinks: { +// twitter?: string; +// discord?: string; +// linkedin?: string; +// website?: string; +// [key: string]: string | undefined; +// } | null; +// approvalStatus: 'pending' | 'approved' | 'rejected'; +// isPinned: boolean; +// hasBeenAcquired: boolean; +// isLookingForContributors: boolean; +// isLookingForInvestors: boolean; +// isHiring: boolean; +// isPublic: boolean; +// isRepoPrivate: boolean; +// acquiredBy: string | null; +// createdAt: Date; +// updatedAt: Date; +// statusId: string; +// typeId: string; +// deletedAt: Date | null; +// status?: { +// id: string; +// name: string; +// displayName?: string; +// }; +// type?: { +// id: string; +// name: string; +// displayName?: string; +// }; +// tagRelations?: Array<{ +// tag?: { +// id?: string; +// name: string; +// displayName?: string; +// }; +// }>; +// } const isValidProvider = ( provider: string | null | undefined, @@ -227,36 +238,6 @@ export default function ProjectPage({ const normalizedProvider = provider === 'gh' ? 'github' : provider === 'gl' ? 'gitlab' : provider; const gitRepoUrl = `${org}/${repoId}`; - const virtualProject = isNotInDatabase - ? { - id: `virtual-${normalizedProvider}-${org}-${repoId}`, - ownerId: null, - logoUrl: null, - gitRepoUrl: gitRepoUrl, - gitHost: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], - name: repoId, - description: null, - socialLinks: null, - approvalStatus: 'approved' as const, - isPinned: false, - hasBeenAcquired: false, - isLookingForContributors: false, - isLookingForInvestors: false, - isHiring: false, - isPublic: true, - isRepoPrivate: false, - acquiredBy: null, - createdAt: new Date(), - updatedAt: new Date(), - statusId: '', - typeId: '', - deletedAt: null, - status: undefined, - type: undefined, - tagRelations: [], - } - : project; - const repoQuery = useQuery( trpc.repository.getRepo.queryOptions( { @@ -264,8 +245,7 @@ export default function ProjectPage({ provider: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], }, { - enabled: - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), + enabled: (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, ), @@ -280,7 +260,7 @@ export default function ProjectPage({ { enabled: !!repoQuery.data && - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, @@ -297,7 +277,7 @@ export default function ProjectPage({ { enabled: !!repoQuery.data && - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, @@ -310,7 +290,7 @@ export default function ProjectPage({ { enabled: !!repoQuery.data && - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, @@ -323,7 +303,7 @@ export default function ProjectPage({ { enabled: !!repoQuery.data && - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, @@ -336,7 +316,7 @@ export default function ProjectPage({ { enabled: !!repoQuery.data && - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, @@ -349,7 +329,7 @@ export default function ProjectPage({ { enabled: !!repoQuery.data && - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, @@ -362,7 +342,7 @@ export default function ProjectPage({ { enabled: !!repoQuery.data && - (!!virtualProject?.gitRepoUrl || isNotInDatabase) && + (!!project?.gitRepoUrl || isNotInDatabase) && isValidProvider(normalizedProvider), retry: false, }, @@ -382,10 +362,6 @@ export default function ProjectPage({ return ; } - if (!virtualProject?.gitRepoUrl) { - return ; - } - if (repoQuery.isLoading) { return (

@@ -398,14 +374,58 @@ export default function ProjectPage({ return repoQuery.refetch()} />; } - const isUnclaimed = !virtualProject.ownerId; - const isOwner = user?.id === virtualProject.ownerId; const repoData = repoQuery.data as Repository; + + const projectData: ProjectWithRelations = isNotInDatabase + ? { + id: `virtual-${normalizedProvider}-${org}-${repoId}`, + ownerId: null, + logoUrl: repoData.owner?.avatar_url || repoData.namespace?.avatar_url || null, + gitRepoUrl: gitRepoUrl, + gitHost: normalizedProvider as (typeof projectProviderEnum.enumValues)[number], + name: repoData.name || repoId, + description: repoData.description || null, + socialLinks: repoData.homepage ? { website: repoData.homepage } : null, + approvalStatus: 'approved' as const, + isPinned: false, + hasBeenAcquired: false, + isLookingForContributors: + repoData.topics?.includes('help-wanted') || + repoData.topics?.includes('good-first-issue') || + false, + isLookingForInvestors: + repoData.topics?.includes('seeking-funding') || + repoData.topics?.includes('investment') || + false, + isHiring: repoData.topics?.includes('hiring') || repoData.topics?.includes('jobs') || false, + isPublic: true, + isRepoPrivate: repoData.isPrivate || repoData.private || false, + acquiredBy: null, + createdAt: repoData.created_at ? new Date(repoData.created_at) : new Date(), + updatedAt: repoData.updated_at ? new Date(repoData.updated_at) : new Date(), + statusId: '', + typeId: '', + deletedAt: null, + status: undefined, + type: undefined, + tagRelations: + repoData.topics?.map((topic: string) => ({ + tag: { + id: topic, + name: topic, + displayName: topic, + }, + })) || [], + } + : project!; + + const isUnclaimed = !projectData.ownerId; + const isOwner = user?.id === projectData.ownerId; const repo = { ...repoData, id: repoData.html_url || repoData.web_url || '', - name: virtualProject.gitRepoUrl?.split('/').pop() || '', - url: repoData.html_url || repoData.web_url || virtualProject.gitRepoUrl || '', + name: projectData.gitRepoUrl?.split('/').pop() || '', + url: repoData.html_url || repoData.web_url || projectData.gitRepoUrl || '', }; const repoStats = repoDataQuery.data as RepoData | undefined; const issuesCount = repoStats?.issuesCount || 0; @@ -430,7 +450,7 @@ export default function ProjectPage({ ) : ( @@ -442,7 +462,7 @@ export default function ProjectPage({
@@ -574,7 +594,7 @@ export default function ProjectPage({ @@ -631,17 +651,17 @@ export default function ProjectPage({ {issuesCount > 10 && ( View all {issuesCount} open issues on{' '} - {virtualProject.gitHost === 'github' ? 'GitHub' : 'GitLab'} → + {projectData.gitHost === 'github' ? 'GitHub' : 'GitLab'} → )}
@@ -702,7 +722,7 @@ export default function ProjectPage({ href={pr.html_url || pr.web_url || '#'} target="_blank" event="project_page_pull_request_link_clicked" - eventObject={{ projectId: virtualProject.id }} + eventObject={{ projectId: projectData.id }} className="mt-2 block text-sm font-medium text-neutral-300 transition-colors hover:text-white" > {pr.title} @@ -753,7 +773,7 @@ export default function ProjectPage({ @@ -765,17 +785,17 @@ export default function ProjectPage({ {pullRequestsCount > 10 && ( View all {pullRequestsCount} open pull requests on{' '} - {virtualProject.gitHost === 'github' ? 'GitHub' : 'GitLab'} → + {projectData.gitHost === 'github' ? 'GitHub' : 'GitLab'} → )}
@@ -861,11 +881,11 @@ export default function ProjectPage({

About

- {virtualProject?.createdAt && ( + {projectData?.createdAt && (
Created @@ -994,7 +1014,7 @@ export default function ProjectPage({
)} - {virtualProject?.updatedAt && ( + {projectData?.updatedAt && (
Updated @@ -1002,16 +1022,16 @@ export default function ProjectPage({
)} - {virtualProject?.gitHost && ( + {projectData?.gitHost && (
Host - {virtualProject?.gitHost} + {projectData?.gitHost}
)}
Visibility - {virtualProject?.isPublic ? 'Public' : 'Private'} + {projectData?.isPublic ? 'Public' : 'Private'}
@@ -1025,7 +1045,7 @@ export default function ProjectPage({ Tags
- {virtualProject?.tagRelations?.map((relation, index: number) => ( + {projectData?.tagRelations?.map((relation, index: number) => ( )} - {virtualProject?.hasBeenAcquired && virtualProject?.acquiredBy && ( + {projectData?.hasBeenAcquired && projectData?.acquiredBy && (
@@ -1046,13 +1066,13 @@ export default function ProjectPage({

This project has been acquired

)} - {(virtualProject?.isLookingForContributors || - virtualProject?.isLookingForInvestors || - virtualProject?.isHiring) && ( + {(projectData?.isLookingForContributors || + projectData?.isLookingForInvestors || + projectData?.isHiring) && (

Opportunities

- {virtualProject?.isLookingForContributors && ( + {projectData?.isLookingForContributors && (
@@ -1063,7 +1083,7 @@ export default function ProjectPage({
)} - {virtualProject?.isLookingForInvestors && ( + {projectData?.isLookingForInvestors && (
@@ -1074,7 +1094,7 @@ export default function ProjectPage({
)} - {virtualProject?.isHiring && ( + {projectData?.isHiring && (
From 8429d826da47a4e2bbeb8dfc335ce36fb6b658cb Mon Sep 17 00:00:00 2001 From: Ahmet Kilinc Date: Sat, 26 Jul 2025 02:15:34 +0100 Subject: [PATCH 4/5] remove comment --- .../(projects)/[provider]/[org]/[repo]/project-description.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx index 5a26c85c..a8595227 100644 --- a/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx +++ b/apps/web/app/(public)/(projects)/[provider]/[org]/[repo]/project-description.tsx @@ -194,8 +194,6 @@ function ProjectDescriptionText({ project }: { project: ProjectWithRelations }) const isLong = description.length > CHAR_LIMIT; const displayText = expanded || !isLong ? description : description.slice(0, CHAR_LIMIT) + '...'; - console.log(description); - return (

Date: Sat, 26 Jul 2025 02:17:53 +0100 Subject: [PATCH 5/5] fix --- .../(public)/launches/[id]/components/launch-sidebar.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/web/app/(public)/launches/[id]/components/launch-sidebar.tsx b/apps/web/app/(public)/launches/[id]/components/launch-sidebar.tsx index 18411d3c..a3f436c2 100644 --- a/apps/web/app/(public)/launches/[id]/components/launch-sidebar.tsx +++ b/apps/web/app/(public)/launches/[id]/components/launch-sidebar.tsx @@ -9,16 +9,16 @@ import { Star, Users, } from 'lucide-react'; -import { Separator } from '@workspace/ui/components/separator'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { Separator } from '@workspace/ui/components/separator'; import { projectProviderEnum } from '@workspace/db/schema'; import { Button } from '@workspace/ui/components/button'; +import { useRouter, usePathname } from 'next/navigation'; import { authClient } from '@workspace/auth/client'; import Link from '@workspace/ui/components/link'; import { formatDistanceToNow } from 'date-fns'; import { useTRPC } from '@/hooks/use-trpc'; import { toast } from 'sonner'; -import { useRouter, usePathname } from 'next/navigation'; const isValidProvider = ( provider: string | null | undefined, @@ -102,6 +102,9 @@ export default function LaunchSidebar({ launch, project, projectId }: LaunchSide const issuesCount = repoStats?.issuesCount || 0; const pullRequestsCount = repoStats?.pullRequestsCount || 0; + const provider = project.gitHost === 'github' ? 'gh' : 'gl'; + const href = `/${provider}/${repoData?.owner.login}/${repoData?.name}`; + return (

{/* Main Info Card */} @@ -216,7 +219,7 @@ export default function LaunchSidebar({ launch, project, projectId }: LaunchSide