-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from AElfProject/feature/github-support
feat: github support
- Loading branch information
Showing
9 changed files
with
682 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
BUILD_SERVER_BASE_URL=https://playground.test.aelf.dev | ||
GA_TAG= | ||
GA_TAG= | ||
GITHUB_API_KEY= |
100 changes: 100 additions & 0 deletions
100
app/https:/github.com/[user]/[repo]/tree/[branch]/[...path]/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import { ImportGitHubForm } from "@/components/import-github-form"; | ||
import { Octokit } from "octokit"; | ||
import { throttling } from "@octokit/plugin-throttling"; | ||
import { getGitHubToken } from "@/lib/env"; | ||
|
||
interface Params { | ||
path: string[]; | ||
user: string; | ||
repo: string; | ||
branch: string; | ||
} | ||
|
||
const MyOctokit = Octokit.plugin(throttling); | ||
|
||
const getData = async ({ path, user, repo, branch }: Params) => { | ||
const octokit = new MyOctokit({ | ||
auth: getGitHubToken(), | ||
throttle: { | ||
onRateLimit: (retryAfter, options, octokit, retryCount) => { | ||
octokit.log.warn( | ||
`Request quota exhausted for request ${options.method} ${options.url}` | ||
); | ||
|
||
if (retryCount < 1) { | ||
// only retries once | ||
octokit.log.info(`Retrying after ${retryAfter} seconds!`); | ||
return true; | ||
} | ||
}, | ||
onSecondaryRateLimit: (retryAfter, options, octokit) => { | ||
// does not retry, only logs a warning | ||
octokit.log.warn( | ||
`SecondaryRateLimit detected for request ${options.method} ${options.url}` | ||
); | ||
}, | ||
}, | ||
}); | ||
|
||
const contents = await octokit.rest.repos.getContent({ | ||
owner: user, | ||
repo, | ||
ref: `heads/${branch}`, | ||
path: path.join("/"), | ||
}); | ||
|
||
const folder = contents.data; | ||
|
||
if (!Array.isArray(folder)) { | ||
return "Not a folder."; | ||
} | ||
|
||
const srcSha = folder?.find((i) => i.name === "src")?.sha; | ||
|
||
if (!srcSha) return "No src folder found."; | ||
|
||
const src = await octokit.rest.git.getTree({ | ||
owner: user, | ||
repo, | ||
tree_sha: srcSha, | ||
recursive: "true", | ||
}); | ||
|
||
const data = src.data.tree; | ||
|
||
let response: { path: string; contents: string }[] = []; | ||
|
||
if (Array.isArray(data)) { | ||
const files = data.filter((i) => i.type === "blob"); | ||
|
||
for (const file of files) { | ||
const blob = await octokit.rest.git.getBlob({ | ||
owner: user, | ||
repo, | ||
file_sha: file.sha!, | ||
}); | ||
|
||
response.push({ | ||
path: `src/${file.path!}`, | ||
contents: Buffer.from(blob.data.content, "base64").toString("ascii"), | ||
}); | ||
} | ||
} | ||
|
||
return response; | ||
}; | ||
|
||
export default async function Page({ | ||
params: { path, user, repo, branch }, | ||
}: { | ||
params: Params; | ||
}) { | ||
const data = await getData({ path, user, repo, branch }); | ||
|
||
return ( | ||
<div className="container px-4 py-12 md:px-6 lg:py-16"> | ||
<h1 className="text-2xl mb-2">Import GitHub repository</h1> | ||
{typeof data === "string" ? data : <ImportGitHubForm data={data} />} | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
"use client"; | ||
|
||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { useForm } from "react-hook-form"; | ||
import { z } from "zod"; | ||
|
||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Form, | ||
FormControl, | ||
FormDescription, | ||
FormField, | ||
FormItem, | ||
FormLabel, | ||
FormMessage, | ||
} from "@/components/ui/form"; | ||
import { Input } from "@/components/ui/input"; | ||
import { useRouter, useParams } from "next/navigation"; | ||
import { db } from "@/data/db"; | ||
import { Loader2 } from "lucide-react"; | ||
|
||
const FormSchema = z.object({ | ||
name: z.string().min(2, { | ||
message: "Name must be at least 2 characters.", | ||
}), | ||
template: z.string(), | ||
}); | ||
|
||
export function ImportGitHubForm(props: { | ||
data: { path: string; contents: string }[]; | ||
}) { | ||
const { path, user, repo, branch } = useParams<{ | ||
path: string[]; | ||
user: string; | ||
repo: string; | ||
branch: string; | ||
}>(); | ||
const form = useForm<z.infer<typeof FormSchema>>({ | ||
resolver: zodResolver(FormSchema), | ||
defaultValues: { | ||
name: "", | ||
template: `github.com/${user}/${repo}/tree/${branch}/${path.join("/")}`, | ||
}, | ||
}); | ||
|
||
const router = useRouter(); | ||
|
||
async function onSubmit(data: z.infer<typeof FormSchema>) { | ||
form.clearErrors(); | ||
try { | ||
await db.workspaces.add({ | ||
name: data.name, | ||
template: data.template, | ||
dll: "", | ||
}); | ||
|
||
await db.files.bulkAdd( | ||
props.data.map(({ path, contents }) => ({ | ||
path: `/workspace/${data.name}/${encodeURIComponent(path)}`, | ||
contents, | ||
})) | ||
); | ||
await router.push(`/workspace/${data.name}`); | ||
} catch (err) { | ||
form.setError("name", { message: String(err) }); | ||
} | ||
} | ||
|
||
return ( | ||
<Form {...form}> | ||
<form onSubmit={form.handleSubmit(onSubmit)} className="w-full space-y-6"> | ||
<FormField | ||
control={form.control} | ||
name="name" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Name</FormLabel> | ||
<FormControl> | ||
<Input | ||
className="w-full" | ||
placeholder="workspace-name" | ||
{...field} | ||
/> | ||
</FormControl> | ||
<FormDescription>This is your workspace name.</FormDescription> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<FormField | ||
control={form.control} | ||
name="template" | ||
render={({ field }) => ( | ||
<FormItem> | ||
<FormLabel>Repo</FormLabel> | ||
<FormControl> | ||
<Input | ||
className="w-full" | ||
placeholder="workspace-name" | ||
{...field} | ||
disabled | ||
/> | ||
</FormControl> | ||
<FormDescription>This is the source repo.</FormDescription> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<Button type="submit" disabled={form.formState.isSubmitting}> | ||
{form.formState.isSubmitting ? ( | ||
<> | ||
<Loader2 className="mr-2 h-4 w-4 animate-spin" /> | ||
Please wait | ||
</> | ||
) : ( | ||
"Submit" | ||
)} | ||
</Button> | ||
</form> | ||
</Form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
"use client"; | ||
|
||
import { zodResolver } from "@hookform/resolvers/zod"; | ||
import { useForm } from "react-hook-form"; | ||
import { z } from "zod"; | ||
|
||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Form, | ||
FormControl, | ||
FormField, | ||
FormItem, | ||
FormMessage, | ||
} from "@/components/ui/form"; | ||
import { Input } from "@/components/ui/input"; | ||
import { useRouter } from "next/navigation"; | ||
import { Loader2 } from "lucide-react"; | ||
|
||
const FormSchema = z.object({ | ||
url: z.string(), | ||
}); | ||
|
||
export function RepoUrlForm() { | ||
const form = useForm<z.infer<typeof FormSchema>>({ | ||
resolver: zodResolver(FormSchema), | ||
defaultValues: { | ||
url: "https://github.com/AElfProject/aelf-developer-tools/tree/master/templates/HelloWorldContract", | ||
}, | ||
}); | ||
|
||
const router = useRouter(); | ||
|
||
async function onSubmit(data: z.infer<typeof FormSchema>) { | ||
form.clearErrors(); | ||
try { | ||
await router.push(`/${data.url}`); | ||
} catch (err) { | ||
form.setError("url", { message: String(err) }); | ||
} | ||
} | ||
|
||
return ( | ||
<Form {...form}> | ||
<form onSubmit={form.handleSubmit(onSubmit)} className="w-full flex"> | ||
<FormField | ||
control={form.control} | ||
name="url" | ||
render={({ field }) => ( | ||
<FormItem className="flex-grow mr-3"> | ||
<FormControl> | ||
<Input placeholder="workspace-name" {...field} /> | ||
</FormControl> | ||
<FormMessage /> | ||
</FormItem> | ||
)} | ||
/> | ||
<Button type="submit" disabled={form.formState.isSubmitting}> | ||
{form.formState.isSubmitting ? ( | ||
<> | ||
<Loader2 className="mr-2 h-4 w-4 animate-spin" /> | ||
Please wait | ||
</> | ||
) : ( | ||
"Submit" | ||
)} | ||
</Button> | ||
</form> | ||
</Form> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.