Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

87 linesCodeBlameRaw
1/**
2 * What a not-found page says. A private project, work item or workspace and one
3 * that does not exist must look the same to someone who cannot see it, so
4 * the words depend only on what kind of thing the address names and on who
5 * is looking, never on whether it exists.
6 */
7
8/** The kind of thing an address names. */
9export type MissingKind = "project" | "item" | "pull" | "workspace" | "person" | "page";
10
11const KINDS: readonly MissingKind[] = ["project", "item", "pull", "workspace", "person", "page"];
12
13/** Names that are pages of g1t itself, never a workspace. */
14const RESERVED = new Set([
15 "settings",
16 "explore",
17 "search",
18 "new",
19 "u",
20 "pricing",
21 "avatars",
22 "workspaces",
23 "login",
24 "logout",
25 "register",
26 "verify",
27 "confirm-email",
28 "forgot",
29 "reset",
30 "device",
31 "oauth",
32 "invite",
33]);
34
35/**
36 * The kind a loader said it could not find (`data({ kind }, { status: 404 })`),
37 * else the kind the address names. Only the shape of the address is used.
38 */
39export function missingKind(errorData: unknown, pathname: string): MissingKind {
40 const said = (errorData as { kind?: unknown } | null | undefined)?.kind;
41 if (typeof said === "string" && (KINDS as readonly string[]).includes(said)) return said as MissingKind;
42 const parts = pathname.split("/").filter(Boolean);
43 if (parts[0] === "u" && parts.length === 2) return "person";
44 if (parts.length === 0 || RESERVED.has(parts[0]!)) return "page";
45 if (parts.length === 1) return "workspace";
46 if (parts[1] === "-") return parts[2] === "work" && parts.length === 4 && /^\d+$/.test(parts[3]!) ? "item" : "page";
47 if (parts.length === 2) return "project";
48 // An old issue's address: what it named, a work item now.
49 if (parts[2] === "issues" && parts.length === 4 && /^\d+$/.test(parts[3]!)) return "item";
50 if (parts[2] === "pull" && parts.length === 4 && /^\d+$/.test(parts[3]!)) return "pull";
51 return "page";
52}
53
54export type NotFoundCopy = {
55 title: string;
56 body: string;
57 /** Who is signed in, for "Signed in as". Null when no one is. */
58 signedInAs: string | null;
59 /** Offer to sign in and come back. */
60 signIn: boolean;
61};
62
63/**
64 * What the page says to whoever is looking. Signed out, it says that the
65 * page may be private, and to sign in if it is yours; signed in, that it
66 * does not exist or they cannot reach it. Never which of the two.
67 */
68export function notFoundCopy(kind: MissingKind, username: string | null | undefined): NotFoundCopy {
69 // People are public: a name either belongs to someone or it does not.
70 if (kind === "person") {
71 return { title: "Nothing here", body: "No one on g1t goes by that name.", signedInAs: null, signIn: false };
72 }
73 if (!username) {
74 return {
75 title: "Nothing here",
76 body: "This page doesn't exist, or it's private. Sign in if it's yours.",
77 signedInAs: null,
78 signIn: true,
79 };
80 }
81 return {
82 title: "Nothing here",
83 body: "This page doesn't exist, or you don't have access to it.",
84 signedInAs: username,
85 signIn: false,
86 };
87}