Skip to content

Commit fd1ad49

Browse files
Some large repo updates
1 parent e22337d commit fd1ad49

File tree

8 files changed

+188
-61
lines changed

8 files changed

+188
-61
lines changed

src/app/(protected)/create/page.tsx

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"use client";
2-
import React, { useRef, useState } from "react";
2+
import React, { useEffect, useRef, useState } from "react";
33
import { useForm } from "react-hook-form";
44
import { zodResolver } from "@hookform/resolvers/zod";
55
import { z } from "zod";
@@ -18,6 +18,7 @@ import { Input } from "@/components/ui/input";
1818
import {
1919
Form,
2020
FormControl,
21+
FormDescription,
2122
FormField,
2223
FormItem,
2324
FormLabel,
@@ -69,13 +70,14 @@ function CreatePage() {
6970
const { createNewProject, isLoading } = useProjects();
7071
const { loadProjects, selectProject } = useProjectsContext();
7172
const isSubmittingRef = useRef(false);
72-
const [loadingSteps, setLoadingSteps] = useState<LoadingStep[]>([
73+
const initialSteps: LoadingStep[] = [
7374
{ id: 1, label: 'Creating project...', status: 'pending', icon: Plus },
7475
{ id: 2, label: 'Loading repository files...', status: 'pending', icon: Github },
7576
{ id: 3, label: 'Analyzing code...', status: 'pending', icon: Code2 },
7677
{ id: 4, label: 'Generating embeddings...', status: 'pending', icon: Sparkles },
7778
{ id: 5, label: 'Creating documentation...', status: 'pending', icon: FileText },
78-
]);
79+
];
80+
const [loadingSteps, setLoadingSteps] = useState<LoadingStep[]>(initialSteps);
7981
const [progress, setProgress] = useState(0);
8082

8183
const form = useForm<CreateProjectForm>({
@@ -88,13 +90,20 @@ function CreatePage() {
8890
});
8991

9092
const updateStep = (stepId: number, status: 'loading' | 'completed') => {
91-
setLoadingSteps(prev =>
92-
prev.map(step =>
93+
setLoadingSteps(prev =>
94+
prev.map(step =>
9395
step.id === stepId ? { ...step, status } : step
9496
)
9597
);
9698
};
9799

100+
useEffect(() => {
101+
const completedSteps = loadingSteps.filter(step => step.status === 'completed').length;
102+
const totalSteps = loadingSteps.length || 1;
103+
const calculatedProgress = Math.round((completedSteps / totalSteps) * 100);
104+
setProgress(calculatedProgress);
105+
}, [loadingSteps]);
106+
98107
const onSubmit = async (data: CreateProjectForm) => {
99108
if (isLoading || isSubmittingRef.current) {
100109
return;
@@ -103,38 +112,35 @@ function CreatePage() {
103112
isSubmittingRef.current = true;
104113

105114
try {
115+
setLoadingSteps(initialSteps);
116+
setProgress(0);
117+
106118
// Step 1: Creating project
107119
updateStep(1, 'loading');
108-
setProgress(10);
109120

110-
const newProject = await createNewProject(data.name, data.githubUrl, process.env.GITHUB_TOKEN);
121+
const newProject = await createNewProject(data.name, data.githubUrl, data.githubToken || undefined);
111122

112123
updateStep(1, 'completed');
113-
setProgress(20);
114124

115125
// Step 2: Loading repository (simulate progress)
116126
updateStep(2, 'loading');
117127
await new Promise(resolve => setTimeout(resolve, 800));
118128
updateStep(2, 'completed');
119-
setProgress(40);
120129

121130
// Step 3: Analyzing code
122131
updateStep(3, 'loading');
123132
await new Promise(resolve => setTimeout(resolve, 1000));
124133
updateStep(3, 'completed');
125-
setProgress(60);
126134

127135
// Step 4: Generating embeddings
128136
updateStep(4, 'loading');
129137
await new Promise(resolve => setTimeout(resolve, 1200));
130138
updateStep(4, 'completed');
131-
setProgress(80);
132139

133140
// Step 5: Creating documentation
134141
updateStep(5, 'loading');
135142
await new Promise(resolve => setTimeout(resolve, 800));
136143
updateStep(5, 'completed');
137-
setProgress(100);
138144

139145
// Refetch projects to get the updated list
140146
await loadProjects();
@@ -235,7 +241,33 @@ function CreatePage() {
235241
)}
236242
/>
237243

238-
244+
<FormField
245+
control={form.control}
246+
name="githubToken"
247+
render={({ field }) => (
248+
<FormItem>
249+
<FormLabel className="flex items-center gap-2 text-white">
250+
<Sparkles className="h-4 w-4" />
251+
GitHub Access Token
252+
<span className="text-xs font-normal text-gray-400">(optional but recommended)</span>
253+
</FormLabel>
254+
<FormControl>
255+
<Input
256+
type="password"
257+
placeholder="ghp_XXXXXXXXXXXXXXXXXXXX"
258+
className="bg-gray-700 border-gray-600 text-white placeholder:text-gray-400 focus:border-blue-500"
259+
autoComplete="off"
260+
{...field}
261+
/>
262+
</FormControl>
263+
<FormDescription className="text-xs text-gray-400">
264+
Provide a GitHub personal access token with <code className="font-mono">repo</code> scope to
265+
avoid rate limits, especially for large repositories.
266+
</FormDescription>
267+
<FormMessage />
268+
</FormItem>
269+
)}
270+
/>
239271

240272
{/* Loading Progress */}
241273
{(form.formState.isSubmitting || isLoading) && (

src/app/(protected)/docs/page.tsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Badge } from '@/components/ui/badge';
99
import { Separator } from '@/components/ui/separator';
1010
import { ScrollArea } from '@/components/ui/scroll-area';
1111
import { Skeleton } from '@/components/ui/skeleton';
12-
import { Alert, AlertDescription } from '@/components/ui/alert';
12+
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
1313
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
1414
import { Input } from '@/components/ui/input';
1515
import {
@@ -109,6 +109,7 @@ function DocsPage() {
109109
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
110110
const [qnaToDelete, setQnaToDelete] = useState<string | null>(null);
111111
const [showDeleteAllDialog, setShowDeleteAllDialog] = useState(false);
112+
const [showProcessingNotice, setShowProcessingNotice] = useState(true);
112113

113114
const selectedProject = projects.find(p => p.id === selectedProjectId);
114115

@@ -204,7 +205,11 @@ function DocsPage() {
204205
});
205206
} catch (err) {
206207
console.error('Error regenerating docs:', err);
207-
const errorMessage = err instanceof Error ? err.message : 'Failed to regenerate documentation';
208+
const rawMessage = err instanceof Error ? err.message : 'Failed to regenerate documentation';
209+
const isRateLimit = rawMessage.toLowerCase().includes('github api rate limit exceeded');
210+
const errorMessage = isRateLimit
211+
? 'GitHub API rate limit hit(this issue is via GitHub API, not RepoDoc). Add a GitHub personal access token when creating the project to avoid this limit.'
212+
: rawMessage;
208213
setError(errorMessage);
209214
toast.error('Failed to regenerate documentation', {
210215
description: errorMessage,
@@ -457,6 +462,28 @@ function DocsPage() {
457462

458463
return (
459464
<div className="h-full flex flex-col mobile-layout">
465+
{showProcessingNotice && (
466+
<Alert className="mx-2 sm:mx-4 mb-4 border-blue-400/40 bg-blue-500/10 text-blue-100">
467+
<AlertTitle className="flex items-center gap-2 text-sm font-semibold text-blue-50">
468+
<Loader2 className="h-4 w-4 animate-spin text-blue-200/80" />
469+
Heads up
470+
</AlertTitle>
471+
<AlertDescription className="mt-2 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 text-sm text-blue-100/90">
472+
<span>
473+
Large repositories can take longer to index, especially on the first load. If GitHub rate limits the request,
474+
add a personal access token with <code className="font-mono">repo</code> scope when creating the project to keep things moving quickly.
475+
</span>
476+
<Button
477+
variant="ghost"
478+
size="icon"
479+
onClick={() => setShowProcessingNotice(false)}
480+
className="self-start sm:self-center text-blue-100/70 hover:text-blue-50"
481+
>
482+
<X className="h-4 w-4" />
483+
</Button>
484+
</AlertDescription>
485+
</Alert>
486+
)}
460487
<div className="flex flex-col sm:flex-row sm:items-center justify-between mb-4 sm:mb-6 mt-2 sm:mt-4 px-2 sm:px-4 gap-3 sm:gap-4">
461488
<div className="flex items-center gap-2 sm:gap-4 flex-1 min-w-0">
462489
<div className="p-2 sm:p-3 bg-white/10 border border-white/20 rounded-xl flex-shrink-0">

src/app/(protected)/readme/page.tsx

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { Badge } from '@/components/ui/badge';
99
import { Separator } from '@/components/ui/separator';
1010
import { ScrollArea } from '@/components/ui/scroll-area';
1111
import { Skeleton } from '@/components/ui/skeleton';
12-
import { Alert, AlertDescription } from '@/components/ui/alert';
12+
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
1313
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
1414
import { Input } from '@/components/ui/input';
1515
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu';
@@ -94,6 +94,7 @@ function ReadmePage() {
9494
const [showDeleteDialog, setShowDeleteDialog] = useState(false);
9595
const [qnaToDelete, setQnaToDelete] = useState<string | null>(null);
9696
const [showDeleteAllDialog, setShowDeleteAllDialog] = useState(false);
97+
const [showProcessingNotice, setShowProcessingNotice] = useState(true);
9798

9899
const selectedProject = projects.find(p => p.id === selectedProjectId);
99100

@@ -189,7 +190,11 @@ function ReadmePage() {
189190
});
190191
} catch (err) {
191192
console.error('Error regenerating README:', err);
192-
const errorMessage = err instanceof Error ? err.message : 'Failed to regenerate README';
193+
const rawMessage = err instanceof Error ? err.message : 'Failed to regenerate README';
194+
const isRateLimit = rawMessage.toLowerCase().includes('github api rate limit exceeded');
195+
const errorMessage = isRateLimit
196+
? 'GitHub rate limit hit. Add a GitHub personal access token (with repo scope) when creating the project to avoid this limit.'
197+
: rawMessage;
193198
setError(errorMessage);
194199
toast.error('Failed to regenerate README', {
195200
description: errorMessage,
@@ -442,6 +447,28 @@ function ReadmePage() {
442447

443448
return (
444449
<div className="h-full flex flex-col mobile-layout">
450+
{showProcessingNotice && (
451+
<Alert className="mx-2 sm:mx-4 mb-4 border-blue-400/40 bg-blue-500/10 text-blue-100">
452+
<AlertTitle className="flex items-center gap-2 text-sm font-semibold text-blue-50">
453+
<Loader2 className="h-4 w-4 animate-spin text-blue-200/80" />
454+
Heads up
455+
</AlertTitle>
456+
<AlertDescription className="mt-2 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 text-sm text-blue-100/90">
457+
<span>
458+
Large repositories can take longer to index, especially on the first load. If GitHub rate limits the request,
459+
add a personal access token with <code className="font-mono">repo</code> scope when creating the project to keep things moving quickly.
460+
</span>
461+
<Button
462+
variant="ghost"
463+
size="icon"
464+
onClick={() => setShowProcessingNotice(false)}
465+
className="self-start sm:self-center text-blue-100/70 hover:text-blue-50"
466+
>
467+
<X className="h-4 w-4" />
468+
</Button>
469+
</AlertDescription>
470+
</Alert>
471+
)}
445472
<div className="flex flex-col sm:flex-row sm:items-center justify-between mb-4 sm:mb-6 mt-2 sm:mt-4 px-2 sm:px-4 gap-3 sm:gap-4">
446473
<div className="flex items-center gap-2 sm:gap-4 flex-1 min-w-0">
447474
<div className="p-2 sm:p-3 bg-white/10 border border-white/20 rounded-xl flex-shrink-0">

src/app/shipping/page.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,19 +38,19 @@ export default function ShippingPolicyPage() {
3838
<p className="mt-3">
3939
Our infrastructure runs on globally distributed servers. Downtime is rare, but in the unlikely event of an
4040
outage we communicate status updates via{" "} {"This functionaility is coming soon. Demo is below."}
41-
<a href="https://status.repodoc.dev" className="text-white underline underline-offset-4">
41+
{/* <a href="https://status.repodoc.dev" className="text-white underline underline-offset-4">
4242
status.repodoc.dev
43-
</a>
43+
</a> */}
4444
.
4545
</p>
4646
</div>
4747

4848
<div>
4949
<h2 className="text-xl font-semibold text-white">Questions</h2>
5050
<p className="mt-3">
51-
If you have questions about your subscription delivery, email{" "}
52-
<a href="mailto:help@productsolution.net" className="text-white underline underline-offset-4">
53-
help@productsolution.net
51+
If you have questions about your subscription delivery, email founder{" "}
52+
<a href="mailto:parbhat@parbhat.dev" className="text-white underline underline-offset-4">
53+
parbhat@parbhat.dev
5454
</a>{" "}
5555
and we&rsquo;ll respond within one business day.
5656
</p>

src/lib/actions.ts

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import { createProjectWithAuth } from './queries';
44
import { auth, currentUser } from '@clerk/nextjs/server';
55
import prisma from './prisma';
6-
import { getGitHubRepositoryInfo } from './github';
6+
import { getGitHubRepositoryInfo, indexGithubRepository } from './github';
77
import { ensureQuotaAvailable, getUsageSnapshot, incrementUsage } from './quota';
88

99
export async function createProject(name: string, githubUrl: string, githubToken?: string) {
@@ -252,7 +252,7 @@ export async function regenerateProjectReadme(projectId: string) {
252252
await ensureQuotaAvailable(userId, 'readme');
253253

254254
// Get all source code summaries for the project
255-
const sourceCodeEmbeddings = await prisma.sourceCodeEmbiddings.findMany({
255+
let sourceCodeEmbeddings = await prisma.sourceCodeEmbiddings.findMany({
256256
where: {
257257
projectId: projectId,
258258
},
@@ -262,7 +262,20 @@ export async function regenerateProjectReadme(projectId: string) {
262262
});
263263

264264
if (sourceCodeEmbeddings.length === 0) {
265-
throw new Error('No source code data found for README generation');
265+
await indexGithubRepository(project.id, project.repoUrl, project.githubToken ?? undefined);
266+
267+
sourceCodeEmbeddings = await prisma.sourceCodeEmbiddings.findMany({
268+
where: {
269+
projectId: projectId,
270+
},
271+
select: {
272+
Summary: true,
273+
},
274+
});
275+
276+
if (sourceCodeEmbeddings.length === 0) {
277+
throw new Error('No source code data found for README generation');
278+
}
266279
}
267280

268281
const summaries = sourceCodeEmbeddings.map(embedding => embedding.Summary);
@@ -690,7 +703,7 @@ export async function regenerateProjectDocs(projectId: string) {
690703
await ensureQuotaAvailable(userId, 'docs');
691704

692705
// Get all source code summaries for the project
693-
const sourceCodeEmbeddings = await prisma.sourceCodeEmbiddings.findMany({
706+
let sourceCodeEmbeddings = await prisma.sourceCodeEmbiddings.findMany({
694707
where: {
695708
projectId: projectId,
696709
},
@@ -700,7 +713,20 @@ export async function regenerateProjectDocs(projectId: string) {
700713
});
701714

702715
if (sourceCodeEmbeddings.length === 0) {
703-
throw new Error('No source code data found for docs generation');
716+
await indexGithubRepository(project.id, project.repoUrl, project.githubToken ?? undefined);
717+
718+
sourceCodeEmbeddings = await prisma.sourceCodeEmbiddings.findMany({
719+
where: {
720+
projectId: projectId,
721+
},
722+
select: {
723+
Summary: true,
724+
},
725+
});
726+
727+
if (sourceCodeEmbeddings.length === 0) {
728+
throw new Error('No source code data found for docs generation');
729+
}
704730
}
705731

706732
const summaries = sourceCodeEmbeddings.map(embedding => embedding.Summary);

0 commit comments

Comments
 (0)