Skip to content
60 linesCodeBlameRaw
1import { ArrowLeft } from "lucide-react";
2import { Form, Link } from "react-router";
3
4import type { AccessToken } from "@g1t/contracts";
5
6import type { Route } from "./+types/token-new";
7import { page } from "../../lib/meta";
8import { ErrorText, SubmitButton } from "../../components/ui";
9import { TokenForm } from "../../components/token-form";
10import { TokenCreated } from "../../components/token-list";
11import { tokenFromForm } from "../../lib/access-tokens";
12import { workspaceChoices } from "../../lib/access-tokens.server";
13import { identity } from "../../lib/services.server";
14import { assertSameOrigin, requireUser } from "../../lib/session.server";
15
16// A new access token of yours: the one form (components/token-form.tsx).
17
18export function meta(args: Route.MetaArgs) {
19 return page(args, { title: "New access token · Settings · g1t" });
20}
21
22export async function loader({ request, context }: Route.LoaderArgs) {
23 const user = requireUser(context, request);
24 return { workspaces: await workspaceChoices(user) };
25}
26
27type ActionResult = { secret: string; token: AccessToken; error: null } | { secret: null; token: null; error: string };
28
29export async function action({ request, context }: Route.ActionArgs): Promise<ActionResult> {
30 assertSameOrigin(request);
31 const user = requireUser(context, request);
32 const input = tokenFromForm(await request.formData());
33 if (!input.ok) return { secret: null, token: null, error: input.error };
34 const created = await identity.createToken(user, input.value);
35 if (!created.ok) return { secret: null, token: null, error: created.error.message };
36 return { secret: created.value.token, token: created.value.info, error: null };
37}
38
39export default function NewToken({ loaderData, actionData }: Route.ComponentProps) {
40 return (
41 <section className="space-y-6">
42 <div>
43 <Link to="/settings/tokens" className="inline-flex items-center gap-1 text-xs text-muted hover:text-fg">
44 <ArrowLeft size={13} /> Access tokens
45 </Link>
46 <h2 className="mt-2 text-lg font-semibold tracking-tight">New access token</h2>
47 <p className="mt-1 text-sm text-muted">It acts as you, never with more than you can do.</p>
48 </div>
49 {actionData?.secret ? (
50 <TokenCreated secret={actionData.secret} token={actionData.token} back="/settings/tokens" />
51 ) : (
52 <Form method="post" className="space-y-6">
53 <TokenForm workspaces={loaderData.workspaces} />
54 <ErrorText>{actionData?.error}</ErrorText>
55 <SubmitButton pending="Generating…">Generate token</SubmitButton>
56 </Form>
57 )}
58 </section>
59 );
60}