Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 1 | import { ArrowLeft, Lock, Plus } from "lucide-react"; |
| Merge branch 'worktree-agent-a985c01f43538af01' | 2 | import { Form, Link, redirect } from "react-router"; |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 3 | |
| 4 | import type { Route } from "./+types/new-github"; | |
| 5 | import { GithubMark } from "../components/github"; | |
| Merge branch 'worktree-agent-a985c01f43538af01' | 6 | import { ButtonLink, ErrorText, Pill, SubmitButton } from "../components/ui"; |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 7 | import { CheckboxOption } from "../components/ui/checkbox"; |
| 8 | import { FieldLegend, FieldSet } from "../components/ui/field"; | |
| 9 | import { RadioCard, RadioGroup } from "../components/ui/radio-group"; | |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 10 | import { MODES, installationSummary, notYetAdded } from "../lib/github"; |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 11 | import { githubApp } from "../lib/github.server"; |
| 12 | import { page } from "../lib/meta"; | |
| 13 | import { assertSameOrigin, requireUser, roleIn } from "../lib/session.server"; | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 14 | import { currentWorkspace } from "../lib/current-workspace.server"; |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 15 | |
| 16 | export function meta(args: Route.MetaArgs) { | |
| 17 | return page(args, { title: "Import from GitHub · g1t" }); | |
| 18 | } | |
| 19 | ||
| 20 | export async function loader({ request, context }: Route.LoaderArgs) { | |
| 21 | const user = requireUser(context, request); | |
| 22 | const url = new URL(request.url); | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 23 | const current = currentWorkspace(user, request); |
| 24 | if (!current) throw redirect("/workspaces/new"); | |
| 25 | const workspace = current.slug; | |
| 26 | const workspaceName = current.name?.trim() || current.slug; | |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 27 | // What the person can see on GitHub is asked for alongside the status: |
| 28 | // an installation made there directly is offered here to be added. | |
| 29 | const [status, visible] = await Promise.all([ | |
| 30 | githubApp.status(user, workspace), | |
| 31 | githubApp.visibleInstallations(user).catch(() => null), | |
| 32 | ]); | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 33 | if (!status.ok || !status.value.configured) throw redirect("/new"); |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 34 | const { installations, linked } = status.value; |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 35 | const recorded = new Set(installations.map((item) => item.id)); |
| 36 | const claimable = | |
| 37 | linked && visible?.ok | |
| 38 | ? notYetAdded(visible.value, workspace) | |
| 39 | .filter((item) => !recorded.has(item.id)) | |
| 40 | .map((item) => ({ ...item, summary: installationSummary(item) })) | |
| 41 | : []; | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 42 | const wanted = Number(url.searchParams.get("installation")); |
| 43 | const installation = installations.find((item) => item.id === wanted) ?? installations[0] ?? null; | |
| 44 | const pageNumber = Math.max(1, Number(url.searchParams.get("page")) || 1); | |
| 45 | let repositories = null; | |
| 46 | let error: string | null = null; | |
| 47 | if (linked && installation) { | |
| 48 | const listed = await githubApp.repositories(user, workspace, installation.id, pageNumber); | |
| 49 | if (listed.ok) repositories = listed.value; | |
| 50 | else error = listed.error.message; | |
| 51 | } | |
| 52 | return { | |
| 53 | workspace, | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 54 | workspaceName, |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 55 | owner: roleIn(user, workspace) === "owner", |
| 56 | linked, | |
| 57 | installations, | |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 58 | claimable, |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 59 | installation, |
| 60 | repositories, | |
| 61 | error, | |
| 62 | requested: url.searchParams.get("requested") === "1", | |
| 63 | }; | |
| 64 | } | |
| 65 | ||
| 66 | export async function action({ request, context }: Route.ActionArgs) { | |
| 67 | assertSameOrigin(request); | |
| 68 | const user = requireUser(context, request); | |
| 69 | const form = await request.formData(); | |
| 70 | const workspace = String(form.get("workspace") ?? ""); | |
| 71 | const installationId = Number(form.get("installation")); | |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 72 | if (form.get("intent") === "add-installation") { |
| 73 | const added = await githubApp.addInstallation(user, workspace, installationId); | |
| 74 | if (!added.ok) return { error: null, addError: added.error.message, results: [] }; | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 75 | throw redirect(`/new/github?installation=${installationId}`); |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 76 | } |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 77 | if (form.get("intent") === "remove-installation") { |
| 78 | const removed = await githubApp.removeInstallation(user, workspace, installationId); | |
| Merge branch 'worktree-agent-a985c01f43538af01' | 79 | // Shown by the list it was removed from, which is there with or without an account chosen. |
| 80 | if (!removed.ok) return { error: null, removeError: removed.error.message, results: [] }; | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 81 | throw redirect("/new/github"); |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 82 | } |
| 83 | const mode = (["import", "mirror", "push"] as const).find((option) => option === form.get("mode")) ?? "import"; | |
| 84 | const chosen = form.getAll("repo").map(Number).filter((id) => Number.isSafeInteger(id) && id > 0).slice(0, 20); | |
| 85 | if (chosen.length === 0) return { error: "Choose at least one repository.", results: [] }; | |
| 86 | const issues = form.get("issues") === "on"; | |
| 87 | // One at a time: each is a copy of a whole repository. | |
| 88 | const results: { id: number; ok: boolean; repo?: string; error?: string }[] = []; | |
| 89 | for (const githubRepoId of chosen) { | |
| 90 | const imported = await githubApp.import(user, workspace, { installationId, githubRepoId, mode, issues }); | |
| 91 | results.push( | |
| 92 | imported.ok | |
| 93 | ? { id: githubRepoId, ok: true, repo: imported.value.repo } | |
| 94 | : { id: githubRepoId, ok: false, error: imported.error.message }, | |
| 95 | ); | |
| 96 | } | |
| 97 | if (results.length === 1 && results[0].ok) throw redirect(`/${results[0].repo}`); | |
| 98 | return { error: null, results }; | |
| 99 | } | |
| 100 | ||
| 101 | export default function NewFromGithub({ loaderData, actionData }: Route.ComponentProps) { | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 102 | const { workspace, workspaceName, installations, claimable, installation, repositories, linked, owner } = loaderData; |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 103 | const these = claimable.length === 1 ? "this account" : "these accounts"; |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 104 | const here = "/new/github"; |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 105 | const names = new Map((repositories?.repositories ?? []).map((repo) => [repo.id, repo.fullName])); |
| 106 | return ( | |
| 107 | <main className="mx-auto max-w-2xl px-4 py-12"> | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 108 | <Link to="/new" className="inline-flex items-center gap-1.5 text-sm text-muted hover:text-fg"> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 109 | <ArrowLeft size={14} /> New project |
| 110 | </Link> | |
| 111 | <span className="mt-6 flex size-10 items-center justify-center rounded-xl bg-accent/10 text-accent ring-1 ring-accent/30"> | |
| 112 | <GithubMark className="size-[18px]" /> | |
| 113 | </span> | |
| 114 | <h1 className="mt-4 text-2xl font-semibold tracking-tight">Import from GitHub</h1> | |
| 115 | <p className="mt-1.5 text-sm text-muted"> | |
| 116 | Bring repositories into <span className="font-mono text-fg">{workspace}</span> through g1t's GitHub App. You choose | |
| 117 | which repositories it can see on GitHub; nothing else is read. | |
| 118 | </p> | |
| 119 | ||
| 120 | ||
| 121 | {!linked ? ( | |
| 122 | <section className="mt-8 rounded-lg border border-line p-6"> | |
| 123 | <h2 className="font-medium">Connect your GitHub account</h2> | |
| 124 | <p className="mt-1.5 text-sm text-muted"> | |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 125 | g1t lists the repositories you can reach on GitHub as you, so it needs your GitHub account linked first. If |
| 126 | the app is installed on GitHub already, it is listed here to add once your account is linked. | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 127 | </p> |
| 128 | <div className="mt-4"> | |
| 129 | <a | |
| 130 | href={`/auth/github?link=1&next=${encodeURIComponent(here)}`} | |
| You choose how g1t looks: Auto follows your system, Light and Dark stay put, set from the account menu, the phone's You and help sheet, Settings → Account or the command palette; the page is drawn in your choice from the first byte, every colour has a light value that reads at 4.5:1 or better, code and diffs are highlighted for both, diagrams and the document editor follow along, the product tour and the g1t mark's avatar stay dark, and Dark is what you see until you choose; the workspaces guide says how. | 131 | className="inline-flex items-center gap-2 rounded-md bg-fg px-3.5 py-2 text-sm font-medium text-bg hover:bg-fg-hover" |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 132 | > |
| 133 | <GithubMark /> Connect GitHub | |
| 134 | </a> | |
| 135 | </div> | |
| 136 | </section> | |
| 137 | ) : ( | |
| 138 | <> | |
| 139 | <section className="mt-8"> | |
| 140 | <div className="flex items-center justify-between gap-4"> | |
| 141 | <h2 className="font-medium">GitHub accounts</h2> | |
| 142 | {owner && ( | |
| 143 | <a | |
| 144 | href={`/integrations/github/install?workspace=${workspace}`} | |
| 145 | className="inline-flex items-center gap-1.5 text-sm text-muted hover:text-fg" | |
| 146 | > | |
| 147 | <Plus size={14} /> Add a GitHub account | |
| 148 | </a> | |
| 149 | )} | |
| 150 | </div> | |
| 151 | {loaderData.requested && ( | |
| 152 | <p className="mt-3 text-sm text-muted"> | |
| 153 | Your request went to the organization's owners on GitHub. Once one approves it, add the account here again. | |
| 154 | </p> | |
| 155 | )} | |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 156 | {claimable.length > 0 && ( |
| 157 | <div className="mt-3 rounded-lg border border-accent/30 bg-accent/5 p-4"> | |
| 158 | <h3 className="text-sm font-medium">Already installed on GitHub</h3> | |
| 159 | <p className="mt-1 text-sm text-muted"> | |
| 160 | {owner | |
| 161 | ? `The app is installed on ${these}, but not added to ${workspaceName} yet.` | |
| 162 | : `The app is installed on ${these}. An owner of ${workspaceName} can add ${claimable.length === 1 ? "it" : "them"} here.`} | |
| 163 | </p> | |
| 164 | <ul className="mt-3 divide-y divide-line rounded-md border border-line bg-bg"> | |
| 165 | {claimable.map((item) => ( | |
| 166 | <li key={item.id} className="flex flex-wrap items-center gap-x-3 gap-y-2 px-4 py-2.5 text-sm"> | |
| 167 | <GithubMark className="size-4 shrink-0 text-muted" /> | |
| 168 | <span className="font-mono">{item.account}</span> | |
| 169 | <span className="whitespace-nowrap text-xs text-faint">{item.summary}</span> | |
| 170 | {item.suspended && <Pill>Suspended</Pill>} | |
| 171 | {owner && ( | |
| 172 | <Form method="post" className="ml-auto"> | |
| 173 | <input type="hidden" name="intent" value="add-installation" /> | |
| 174 | <input type="hidden" name="workspace" value={workspace} /> | |
| 175 | <input type="hidden" name="installation" value={item.id} /> | |
| 176 | <SubmitButton | |
| 177 | pending="Adding…" | |
| 178 | match={{ intent: "add-installation", installation: String(item.id) }} | |
| 179 | > | |
| 180 | Add to {workspaceName} | |
| 181 | </SubmitButton> | |
| 182 | </Form> | |
| 183 | )} | |
| 184 | </li> | |
| 185 | ))} | |
| 186 | </ul> | |
| 187 | <ErrorText>{actionData && "addError" in actionData ? actionData.addError : null}</ErrorText> | |
| 188 | </div> | |
| 189 | )} | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 190 | {installations.length === 0 ? ( |
| 191 | <div className="mt-3 rounded-lg border border-dashed border-line p-6 text-sm text-muted"> | |
| 192 | {owner ? ( | |
| 193 | <> | |
| A GitHub App installed straight on GitHub can be added to a workspace: Import from GitHub lists the installations your GitHub account can see that this workspace hasn't added, each with Add for owners, and coming back from GitHub without g1t's own start asks which of your workspaces to add it to instead of stopping; the GitHub guide says how. | 194 | <p> |
| 195 | {claimable.length > 0 | |
| 196 | ? "Or install g1t's GitHub App on another GitHub account or organization, and choose the repositories it may see." | |
| 197 | : "Install g1t's GitHub App on your GitHub account or an organization, and choose the repositories it may see."} | |
| 198 | </p> | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 199 | <div className="mt-4"> |
| 200 | <a | |
| 201 | href={`/integrations/github/install?workspace=${workspace}`} | |
| You choose how g1t looks: Auto follows your system, Light and Dark stay put, set from the account menu, the phone's You and help sheet, Settings → Account or the command palette; the page is drawn in your choice from the first byte, every colour has a light value that reads at 4.5:1 or better, code and diffs are highlighted for both, diagrams and the document editor follow along, the product tour and the g1t mark's avatar stay dark, and Dark is what you see until you choose; the workspaces guide says how. | 202 | className="inline-flex items-center gap-2 rounded-md bg-fg px-3.5 py-2 text-sm font-medium text-bg hover:bg-fg-hover" |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 203 | > |
| 204 | <GithubMark /> Install on GitHub | |
| 205 | </a> | |
| 206 | </div> | |
| 207 | </> | |
| 208 | ) : ( | |
| 209 | <p>No GitHub account is connected to this workspace yet. Ask one of its owners to add one.</p> | |
| 210 | )} | |
| 211 | </div> | |
| 212 | ) : ( | |
| 213 | <ul className="mt-3 divide-y divide-line rounded-md border border-line"> | |
| 214 | {installations.map((item) => ( | |
| 215 | <li key={item.id} className="flex flex-wrap items-center gap-x-3 gap-y-1 px-4 py-2.5 text-sm"> | |
| 216 | <Link | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 217 | to={`${here}?installation=${item.id}`} |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 218 | className={`whitespace-nowrap ${item.id === installation?.id ? "font-medium text-fg" : "text-muted hover:text-fg"}`} |
| 219 | > | |
| 220 | {item.account} | |
| 221 | </Link> | |
| 222 | <span className="whitespace-nowrap text-xs text-faint"> | |
| 223 | {item.accountType === "Organization" ? "Organization" : "Personal"} ·{" "} | |
| 224 | {item.repositorySelection === "all" ? "all repositories" : "selected repositories"} | |
| 225 | </span> | |
| 226 | {item.suspended && <Pill>Suspended</Pill>} | |
| 227 | <span className="ml-auto flex items-center gap-3"> | |
| 228 | <a href={item.settingsUrl} className="whitespace-nowrap text-xs text-muted hover:text-fg" target="_blank" rel="noreferrer"> | |
| 229 | Choose repositories on GitHub | |
| 230 | </a> | |
| 231 | {owner && ( | |
| 232 | <Form method="post"> | |
| 233 | <input type="hidden" name="intent" value="remove-installation" /> | |
| 234 | <input type="hidden" name="workspace" value={workspace} /> | |
| 235 | <input type="hidden" name="installation" value={item.id} /> | |
| Merge branch 'worktree-agent-a985c01f43538af01' | 236 | <SubmitButton |
| 237 | pending="Removing…" | |
| 238 | match={{ intent: "remove-installation", installation: String(item.id) }} | |
| 239 | className="inline-flex items-center gap-1 text-xs text-faint hover:text-danger disabled:opacity-50" | |
| 240 | > | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 241 | Remove |
| Merge branch 'worktree-agent-a985c01f43538af01' | 242 | </SubmitButton> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 243 | </Form> |
| 244 | )} | |
| 245 | </span> | |
| 246 | </li> | |
| 247 | ))} | |
| 248 | </ul> | |
| 249 | )} | |
| Merge branch 'worktree-agent-a985c01f43538af01' | 250 | <ErrorText>{actionData && "removeError" in actionData ? actionData.removeError : null}</ErrorText> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 251 | </section> |
| 252 | ||
| 253 | {installation && ( | |
| 254 | <Form method="post" className="mt-10 space-y-8"> | |
| Merge branch 'worktree-agent-a985c01f43538af01' | 255 | <input type="hidden" name="intent" value="import" /> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 256 | <input type="hidden" name="workspace" value={workspace} /> |
| 257 | <input type="hidden" name="installation" value={installation.id} /> | |
| 258 | <FieldSet> | |
| 259 | <FieldLegend>Repositories on {installation.account}</FieldLegend> | |
| 260 | <ErrorText>{loaderData.error}</ErrorText> | |
| 261 | {repositories && repositories.repositories.length === 0 && ( | |
| 262 | <p className="text-sm text-muted"> | |
| 263 | The app cannot see any repositories here yet.{" "} | |
| 264 | <a href={installation.settingsUrl} className="text-fg underline underline-offset-4"> | |
| 265 | Choose some on GitHub | |
| 266 | </a> | |
| 267 | . | |
| 268 | </p> | |
| 269 | )} | |
| 270 | <div className="divide-y divide-line rounded-md border border-line empty:hidden"> | |
| 271 | {(repositories?.repositories ?? []).map((repo) => ( | |
| 272 | <div key={repo.id} className="px-4 py-3"> | |
| 273 | <CheckboxOption | |
| 274 | name="repo" | |
| 275 | value={String(repo.id)} | |
| 276 | disabled={repo.linkedTo != null} | |
| 277 | label={ | |
| 278 | <span className="flex flex-wrap items-center gap-2"> | |
| 279 | <span className="font-mono">{repo.fullName}</span> | |
| 280 | {repo.private && ( | |
| 281 | <span className="inline-flex items-center gap-1 text-xs text-faint"> | |
| 282 | <Lock size={11} /> Private | |
| 283 | </span> | |
| 284 | )} | |
| 285 | {repo.linkedTo && <Pill>On g1t as {repo.linkedTo}</Pill>} | |
| 286 | </span> | |
| 287 | } | |
| 288 | description={repo.description ?? undefined} | |
| 289 | /> | |
| 290 | </div> | |
| 291 | ))} | |
| 292 | </div> | |
| 293 | {repositories && repositories.total > repositories.perPage && ( | |
| 294 | <div className="flex justify-between text-sm"> | |
| 295 | {repositories.page > 1 ? ( | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 296 | <Link to={`${here}?installation=${installation.id}&page=${repositories.page - 1}`} className="text-muted hover:text-fg"> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 297 | Previous |
| 298 | </Link> | |
| 299 | ) : ( | |
| 300 | <span /> | |
| 301 | )} | |
| 302 | {repositories.page * repositories.perPage < repositories.total && ( | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 303 | <Link to={`${here}?installation=${installation.id}&page=${repositories.page + 1}`} className="text-muted hover:text-fg"> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 304 | Next |
| 305 | </Link> | |
| 306 | )} | |
| 307 | </div> | |
| 308 | )} | |
| 309 | </FieldSet> | |
| 310 | ||
| 311 | <FieldSet> | |
| 312 | <FieldLegend>How it comes across</FieldLegend> | |
| 313 | <RadioGroup name="mode" defaultValue="import" aria-label="How it comes across" className="gap-3 sm:grid-cols-3"> | |
| 314 | {MODES.map((mode) => ( | |
| 315 | <RadioCard key={mode.id} value={mode.id} title={mode.title} description={mode.text} /> | |
| 316 | ))} | |
| 317 | </RadioGroup> | |
| 318 | </FieldSet> | |
| 319 | ||
| 320 | <CheckboxOption | |
| 321 | name="issues" | |
| 322 | defaultChecked | |
| 323 | label="Copy issues too" | |
| Git storage hardened, pages in tens of milliseconds, honest security alerts, and costs reconciled daily | 324 | description="Up to 200 per repository, with their labels and whether they are open; a milestone is noted in the description. Pull requests stay on GitHub; their branches come across." |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 325 | /> |
| 326 | ||
| 327 | {actionData?.results && actionData.results.length > 0 && ( | |
| 328 | <ul className="space-y-1 rounded-md border border-line p-4 text-sm"> | |
| 329 | {actionData.results.map((result) => ( | |
| 330 | <li key={result.id}> | |
| 331 | <span className="font-mono">{names.get(result.id) ?? result.id}</span>:{" "} | |
| 332 | {result.ok ? ( | |
| 333 | <Link to={`/${result.repo}`} className="text-accent underline underline-offset-4"> | |
| 334 | {result.repo} | |
| 335 | </Link> | |
| 336 | ) : ( | |
| 337 | <span className="text-danger">{result.error}</span> | |
| 338 | )} | |
| 339 | </li> | |
| 340 | ))} | |
| 341 | </ul> | |
| 342 | )} | |
| 343 | <ErrorText>{actionData?.error}</ErrorText> | |
| 344 | <div className="flex items-center gap-3"> | |
| Merge branch 'worktree-agent-a985c01f43538af01' | 345 | <SubmitButton variant="accent" pending="Bringing them across…" match={{ intent: "import" }}> |
| 346 | Bring to g1t | |
| 347 | </SubmitButton> | |
| New project and Import from GitHub work in the workspace you're in, as the sidebar shows it, with no workspace to pick on the page; a link that names another of your workspaces switches you to it first. The projects guide says so. | 348 | <ButtonLink to="/new" variant="quiet"> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 349 | Cancel |
| 350 | </ButtonLink> | |
| 351 | </div> | |
| 352 | </Form> | |
| 353 | )} | |
| 354 | </> | |
| 355 | )} | |
| 356 | </main> | |
| 357 | ); | |
| 358 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.