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.
| Automations: rules in .g1t/automations that act when something happens | 1 | import { CircleCheck, MailWarning } from "lucide-react"; |
| 2 | import { redirect } from "react-router"; | |
| 3 | ||
| 4 | import type { Route } from "./+types/verify"; | |
| Social cards for every page: og.g1t.sh | 5 | import { page } from "../lib/meta"; |
| Automations: rules in .g1t/automations that act when something happens | 6 | import { ButtonLink } from "../components/ui"; |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 7 | import { CONFIRM_PATH, afterConfirming, confirmedLine } from "../lib/confirm-gate"; |
| Automations: rules in .g1t/automations that act when something happens | 8 | import { identity } from "../lib/services.server"; |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 9 | import { assertSameOrigin, getViewer, requireUser } from "../lib/session.server"; |
| Automations: rules in .g1t/automations that act when something happens | 10 | |
| Social cards for every page: og.g1t.sh | 11 | export function meta(args: Route.MetaArgs) { |
| 12 | return page(args, { title: "Confirm your email · g1t" }); | |
| Automations: rules in .g1t/automations that act when something happens | 13 | } |
| 14 | ||
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 15 | /** |
| 16 | * Follows the link from the confirmation email, signed in or not: the same | |
| 17 | * email's code does the same on /confirm-email. | |
| 18 | */ | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 19 | export async function loader({ request, context }: Route.LoaderArgs) { |
| Automations: rules in .g1t/automations that act when something happens | 20 | const token = new URL(request.url).searchParams.get("token") ?? ""; |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 21 | const viewer = getViewer(context); |
| Automations: rules in .g1t/automations that act when something happens | 22 | const result = await identity.verifyEmail(token); |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 23 | if (!result.ok) return { ok: false as const, message: result.error.message, signedIn: viewer != null }; |
| 24 | const done = result.value; | |
| 25 | // An address added to an account in use goes back to settings; a new | |
| 26 | // account's first goes on to the workspace its invite joined, or home. | |
| 27 | const added = viewer?.verified === true; | |
| 28 | return { | |
| 29 | ok: true as const, | |
| 30 | username: done.username, | |
| 31 | added, | |
| 32 | line: confirmedLine(done), | |
| 33 | lapsed: Boolean(done.inviteLapsed), | |
| Merge workspace invitations: nobody joins a workspace without saying yes, people are found by username, your own invites can bring someone in, and nobody is left without a workspace (identity 0040) | 34 | to: afterConfirming("/", done.joined, done.invitedTo), |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 35 | signedIn: viewer != null, |
| 36 | }; | |
| Automations: rules in .g1t/automations that act when something happens | 37 | } |
| 38 | ||
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 39 | /** An old form's "resend": the confirmation page sends new codes now. */ |
| Automations: rules in .g1t/automations that act when something happens | 40 | export async function action({ request, context }: Route.ActionArgs) { |
| 41 | assertSameOrigin(request); | |
| 42 | await identity.resendVerification(requireUser(context, request)); | |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 43 | throw redirect(CONFIRM_PATH); |
| Automations: rules in .g1t/automations that act when something happens | 44 | } |
| 45 | ||
| 46 | export default function Verify({ loaderData }: Route.ComponentProps) { | |
| 47 | return ( | |
| g1t is described as the product it is in alpha, and its shell takes the new shape: the README, the docs home and docs/PLAN.md label every feature Live, Preview or Coming; a floating dock with the g1t mark, Today, Chat, Notifications, Agents, Code, Artifacts, your pinned apps and the Apps launcher, with People, Workspace and the account menu (now holding help) at its foot; the workspace's logo and switcher heading a flat sidebar that folds away with Ctrl B, or leading the header's breadcrumbs where there is none; the page in a rounded panel with a full-width header; Today as the front page, with first-time acceptance of agents' pull requests, what needs you and what's at stake, spend today and one item to start with, every number from a service; Notifications in place of the Inbox at /notifications; a bottom bar and More sheet on phones; and sign-in, sign-up, two-factor, reset, invites and choosing a workspace on standalone pages with no app around them. | 48 | <main className="mx-auto max-w-md pt-10 text-center"> |
| Automations: rules in .g1t/automations that act when something happens | 49 | {loaderData.ok ? ( |
| 50 | <> | |
| Merge branch 'worktree-agent-ad7c6d88d93adc817' | 51 | <CircleCheck size={40} className="mx-auto text-success" /> |
| Automations: rules in .g1t/automations that act when something happens | 52 | <h1 className="mt-6 text-2xl font-semibold tracking-tight"> |
| 53 | Email confirmed | |
| 54 | </h1> | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 55 | {loaderData.added ? ( |
| 56 | <> | |
| 57 | <p className="mt-2 text-muted"> | |
| 58 | The address is confirmed on {loaderData.username}. You can make it | |
| 59 | your primary address in your settings. | |
| 60 | </p> | |
| 61 | <div className="mt-8"> | |
| status.g1t.sh with incident management, invites that land you in the workspace, settings as pages, usage without quotas | 62 | <ButtonLink to="/settings/emails">Back to settings</ButtonLink> |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 63 | </div> |
| 64 | </> | |
| 65 | ) : ( | |
| 66 | <> | |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 67 | <p className={`mt-2 ${loaderData.lapsed ? "text-fg" : "text-muted"}`} role="status"> |
| 68 | {loaderData.line} Your account {loaderData.username} is ready. | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 69 | </p> |
| 70 | <div className="mt-8"> | |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 71 | <ButtonLink to={loaderData.signedIn ? loaderData.to : `/login?next=${encodeURIComponent(loaderData.to)}`}> |
| 72 | {loaderData.signedIn ? "Continue" : "Sign in"} | |
| 73 | </ButtonLink> | |
| Invite-only launch: sign in with GitHub, repository access and lifecycle, many emails, a new look | 74 | </div> |
| 75 | </> | |
| 76 | )} | |
| Automations: rules in .g1t/automations that act when something happens | 77 | </> |
| 78 | ) : ( | |
| 79 | <> | |
| 80 | <MailWarning size={40} className="mx-auto text-warn" /> | |
| 81 | <h1 className="mt-6 text-2xl font-semibold tracking-tight"> | |
| 82 | That link did not work | |
| 83 | </h1> | |
| 84 | <p className="mt-2 text-muted">{loaderData.message}</p> | |
| 85 | <p className="mt-2 text-sm text-muted"> | |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 86 | Links work once, for an hour, and a newer email replaces them. |
| 87 | {loaderData.signedIn | |
| 88 | ? " Enter the code from your latest email, or send a new one." | |
| 89 | : " Sign in to enter the code from the email, or to send a new one."} | |
| Automations: rules in .g1t/automations that act when something happens | 90 | </p> |
| 91 | <div className="mt-8"> | |
| Merge email confirmation gate: a code and a link, nothing until confirmed (identity 0036) | 92 | <ButtonLink to={loaderData.signedIn ? CONFIRM_PATH : `/login?next=${encodeURIComponent(CONFIRM_PATH)}`} variant="quiet"> |
| 93 | {loaderData.signedIn ? "Enter a code" : "Sign in"} | |
| Automations: rules in .g1t/automations that act when something happens | 94 | </ButtonLink> |
| 95 | </div> | |
| 96 | </> | |
| 97 | )} | |
| 98 | </main> | |
| 99 | ); | |
| 100 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.