Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions app/[owner]/[repo]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Metadata } from 'next'

interface LayoutProps {
params: Promise<{
owner: string
repo: string
}>
children: React.ReactNode
}

export async function generateMetadata({ params }: LayoutProps): Promise<Metadata> {
const { owner, repo } = await params

return {
title: `${owner}/${repo} - Coding Agent`,
description: `Create AI-powered tasks for ${owner}/${repo}`,
}
}

export default function Layout({ children }: LayoutProps) {
return children
}
41 changes: 41 additions & 0 deletions app/[owner]/[repo]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { cookies } from 'next/headers'
import { HomePageContent } from '@/components/home-page-content'
import { getServerSession } from '@/lib/session/get-server-session'
import { getGitHubStars } from '@/lib/github-stars'
import { getMaxSandboxDuration } from '@/lib/db/settings'

interface OwnerRepoPageProps {
params: Promise<{
owner: string
repo: string
}>
}

export default async function OwnerRepoPage({ params }: OwnerRepoPageProps) {
const { owner, repo } = await params

const cookieStore = await cookies()
const installDependencies = cookieStore.get('install-dependencies')?.value === 'true'
const keepAlive = cookieStore.get('keep-alive')?.value === 'true'

const session = await getServerSession()

// Get max sandbox duration for this user (user-specific > global > env var)
const maxSandboxDuration = await getMaxSandboxDuration(session?.user?.id)
const maxDuration = parseInt(cookieStore.get('max-duration')?.value || maxSandboxDuration.toString(), 10)

const stars = await getGitHubStars()

return (
<HomePageContent
initialSelectedOwner={owner}
initialSelectedRepo={repo}
initialInstallDependencies={installDependencies}
initialMaxDuration={maxDuration}
initialKeepAlive={keepAlive}
maxSandboxDuration={maxSandboxDuration}
user={session?.user ?? null}
initialStars={stars}
/>
)
}
58 changes: 58 additions & 0 deletions app/api/github/verify-repo/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { NextRequest, NextResponse } from 'next/server'
import { getUserGitHubToken } from '@/lib/github/user-token'

export async function GET(request: NextRequest) {
try {
const token = await getUserGitHubToken(request)

if (!token) {
return NextResponse.json({ error: 'GitHub not connected' }, { status: 401 })
}

const { searchParams } = new URL(request.url)
const owner = searchParams.get('owner')
const repo = searchParams.get('repo')

if (!owner || !repo) {
return NextResponse.json({ error: 'Owner and repo parameters are required' }, { status: 400 })
}

// Try to fetch the repository to check if it's accessible
const response = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
headers: {
Authorization: `Bearer ${token}`,
Accept: 'application/vnd.github.v3+json',
},
})

if (!response.ok) {
if (response.status === 404) {
return NextResponse.json({ accessible: false, error: 'Repository not found' }, { status: 200 })
}
return NextResponse.json({ accessible: false, error: 'Failed to verify repository' }, { status: 200 })
}

const repoData = await response.json()

// Return repo info including owner details
return NextResponse.json({
accessible: true,
owner: {
login: repoData.owner.login,
name: repoData.owner.login, // Use login as name if name is not available
avatar_url: repoData.owner.avatar_url,
},
repo: {
name: repoData.name,
full_name: repoData.full_name,
description: repoData.description,
private: repoData.private,
clone_url: repoData.clone_url,
language: repoData.language,
},
})
} catch (error) {
console.error('Error verifying GitHub repository:', error)
return NextResponse.json({ accessible: false, error: 'Failed to verify repository' }, { status: 500 })
}
}
22 changes: 22 additions & 0 deletions app/new/[owner]/[repo]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Metadata } from 'next'

interface LayoutProps {
params: Promise<{
owner: string
repo: string
}>
children: React.ReactNode
}

export async function generateMetadata({ params }: LayoutProps): Promise<Metadata> {
const { owner, repo } = await params

return {
title: `${owner}/${repo} - Coding Agent`,
description: `Create AI-powered tasks for ${owner}/${repo}`,
}
}

export default function Layout({ children }: LayoutProps) {
return children
}
41 changes: 41 additions & 0 deletions app/new/[owner]/[repo]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { cookies } from 'next/headers'
import { HomePageContent } from '@/components/home-page-content'
import { getServerSession } from '@/lib/session/get-server-session'
import { getGitHubStars } from '@/lib/github-stars'
import { getMaxSandboxDuration } from '@/lib/db/settings'

interface NewRepoPageProps {
params: Promise<{
owner: string
repo: string
}>
}

export default async function NewRepoPage({ params }: NewRepoPageProps) {
const { owner, repo } = await params

const cookieStore = await cookies()
const installDependencies = cookieStore.get('install-dependencies')?.value === 'true'
const keepAlive = cookieStore.get('keep-alive')?.value === 'true'

const session = await getServerSession()

// Get max sandbox duration for this user (user-specific > global > env var)
const maxSandboxDuration = await getMaxSandboxDuration(session?.user?.id)
const maxDuration = parseInt(cookieStore.get('max-duration')?.value || maxSandboxDuration.toString(), 10)

const stars = await getGitHubStars()

return (
<HomePageContent
initialSelectedOwner={owner}
initialSelectedRepo={repo}
initialInstallDependencies={installDependencies}
initialMaxDuration={maxDuration}
initialKeepAlive={keepAlive}
maxSandboxDuration={maxSandboxDuration}
user={session?.user ?? null}
initialStars={stars}
/>
)
}
4 changes: 2 additions & 2 deletions components/home-page-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,8 @@ export function HomePageContent({
/>
</div>

{/* Mobile Footer with Stars and Deploy Button - Only show when logged in */}
{user && <HomePageMobileFooter initialStars={initialStars} />}
{/* Mobile Footer with Stars and Deploy Button - Show when logged in OR when owner/repo are selected */}
{(user || selectedOwner || selectedRepo) && <HomePageMobileFooter initialStars={initialStars} />}

{/* Sign In Dialog */}
<Dialog open={showSignInDialog} onOpenChange={setShowSignInDialog}>
Expand Down
17 changes: 13 additions & 4 deletions components/home-page-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,13 +191,13 @@ export function HomePageHeader({

const actions = (
<div className="flex items-center gap-2 flex-shrink-0">
{/* GitHub Stars Button - Show on mobile only when logged out, always show on desktop */}
<div className={user ? 'hidden md:block' : 'block'}>
{/* GitHub Stars Button - Show on mobile only when logged out (unless owner/repo selected), always show on desktop */}
<div className={user ? 'hidden md:block' : selectedOwner || selectedRepo ? 'hidden' : 'block md:block'}>
<GitHubStarsButton initialStars={initialStars} />
</div>

{/* Deploy to Vercel Button - Show on mobile only when logged out, always show on desktop */}
<div className={user ? 'hidden md:block' : 'block'}>
{/* Deploy to Vercel Button - Show on mobile only when logged out (unless owner/repo selected), always show on desktop */}
<div className={user ? 'hidden md:block' : selectedOwner || selectedRepo ? 'hidden' : 'block md:block'}>
<Button
asChild
variant="outline"
Expand Down Expand Up @@ -293,6 +293,15 @@ export function HomePageHeader({
<GitHubIcon className="h-4 w-4 mr-2" />
Connect GitHub
</Button>
) : selectedOwner || selectedRepo ? (
// Show RepoSelector when logged out if owner/repo are provided via URL
<RepoSelector
selectedOwner={selectedOwner}
selectedRepo={selectedRepo}
onOwnerChange={onOwnerChange}
onRepoChange={onRepoChange}
size="sm"
/>
) : null}
</div>
)
Expand Down
Loading
Loading