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.

105 linesCodeBlameRaw
1/**
2 * Your own settings: one page for each part, at `/settings/<page>`, so the
3 * docs, emails and messages can link to exactly the one they mean.
4 */
5
6import { G1T_INVITES } from "./invites.ts";
7
8export type AccountSettingsPage =
9 | "profile"
10 | "emails"
11 | "notifications"
12 | "invites"
13 | "keys"
14 | "tokens"
15 | "integrations"
16 | "github"
17 | "applications"
18 | "two-factor"
19 | "security-log"
20 | "account";
21
22/** Each page's name and what it is for, in the sidebar's order. */
23export const ACCOUNT_SETTINGS: Record<AccountSettingsPage, { title: string; about: string; heading?: string }> = {
24 profile: { title: "Profile", about: "Your picture, and what everyone sees on your profile." },
25 emails: {
26 title: "Emails",
27 about:
28 "Your primary address gets account mail and password resets. Any confirmed address signs you in and can reset your password, and commits that carry it are shown as yours.",
29 },
30 notifications: {
31 title: "Notifications",
32 about: "What you are also emailed for, and how you watch repositories. Everything comes to your notifications either way.",
33 },
34 // Invite a friend: an invite to g1t, not a workspace's invitation (lib/invites.ts, G1T_INVITES).
35 invites: {
36 title: G1T_INVITES.nav,
37 heading: G1T_INVITES.heading,
38 about: G1T_INVITES.about,
39 },
40 keys: { title: "SSH keys", about: "Keys that let git on your computers reach g1t as you." },
41 tokens: {
42 title: "Access tokens",
43 about: "Use a token as the password when git asks for one over HTTPS, and to authenticate agents and the API. A token here acts as you.",
44 },
45 integrations: {
46 title: "Integrations",
47 heading: "Your integrations",
48 about:
49 "Your own accounts, connected just for you and working in every workspace you belong to, such as your calendar setting your status. Tools the whole team shares are a workspace's.",
50 },
51 github: {
52 title: "GitHub",
53 about: "Sign in with your GitHub account, and import repositories you can reach there.",
54 },
55 applications: {
56 title: "Connected applications",
57 about: "Applications you signed in to through your browser, such as an agent connected to the g1t MCP server. Signing one out ends its access at once.",
58 },
59 "two-factor": {
60 title: "Two-factor authentication",
61 about: "A code from an app on your phone as well as your password when you sign in. Workspaces can require it of their members.",
62 },
63 "security-log": {
64 title: "Security log",
65 about:
66 "Changes to your addresses, password, two-factor authentication, keys, tokens and applications, by you or by g1t staff. If you do not recognise one, reset your password.",
67 },
68 account: {
69 title: "Account",
70 about: "Your username, how g1t looks to you, and deleting your account.",
71 },
72};
73
74/** Where the first page is: `/settings` goes there. */
75export const FIRST_SETTINGS_PAGE = "/settings/profile";
76
77/**
78 * The sections of the old single settings page, by their `#anchor`, and
79 * the page each now has. Links like `g1t.sh/settings#emails` in old email
80 * and bookmarks still land in the right place.
81 */
82const OLD_ANCHORS: Record<string, AccountSettingsPage> = {
83 picture: "profile",
84 profile: "profile",
85 emails: "emails",
86 github: "github",
87 invites: "invites",
88 "ssh-keys": "keys",
89 tokens: "tokens",
90 applications: "applications",
91 "security-log": "security-log",
92};
93
94/** The page an old `#anchor` of the settings page now lives at, if it was one. */
95export function settingsPathForHash(hash: string): string | null {
96 const page = OLD_ANCHORS[hash.replace(/^#/, "")];
97 return page ? `/settings/${page}` : null;
98}
99
100/** Which settings page a path is, or null when it is none. A page within one (a token under Access tokens) is that page's. */
101export function accountSettingsPage(pathname: string): AccountSettingsPage | null {
102 const match = /^\/settings\/([^/]+)(?:\/.*)?$/.exec(pathname);
103 const page = match?.[1];
104 return page && page in ACCOUNT_SETTINGS ? (page as AccountSettingsPage) : null;
105}