diff --git a/client/src/components/settings/GitIdentitySettings.tsx b/client/src/components/settings/GitIdentitySettings.tsx index bd605afb..90381c48 100644 --- a/client/src/components/settings/GitIdentitySettings.tsx +++ b/client/src/components/settings/GitIdentitySettings.tsx @@ -7,7 +7,9 @@ * keys a clone (Add workspace → Clone) and the pushes from that clone use — * an ED25519 and/or an RSA one (AWS CodeCommit takes only RSA) — make one, copy its public half to add to GitHub/GitLab, replace or delete * it, and whether git typed in the account's own terminal uses it too (a - * switch over `core.sshCommand` in its `~/.gitconfig`, issue #82) — and, for + * switch over `core.sshCommand` in its `~/.gitconfig`, issue #82), the SSH + * login name per host (AWS CodeCommit's SSH key ID, a `url.<…>.insteadOf` in + * that same file, so a plain `ssh://git-codecommit…` URL works) — and, for * a user with their own Linux account (S3), their own HTTPS * logins. The host account's HTTPS logins are the shared Git credentials * table above it, so this lists them only for a member. The private key and @@ -15,7 +17,7 @@ * seen by a non-admin is read-only. * @author Nguyễn Ngọc Trí Vĩ */ -import { useCallback, useEffect, useState } from "react"; +import { useCallback, useEffect, useState, type ReactNode } from "react"; import { useTranslation } from "react-i18next"; import { Copy, KeyRound, Plus, RefreshCw, Trash2 } from "lucide-react"; import { api, type GitIdentity } from "../../lib/api"; @@ -30,6 +32,140 @@ const INPUT = const BTN = "inline-flex items-center gap-1.5 rounded border border-border-light px-2.5 py-1 text-xs text-fg-secondary hover:bg-surface-3 disabled:cursor-not-allowed disabled:opacity-40"; +const CODECOMMIT_RE = /^git-codecommit\.([a-z0-9-]+)\.amazonaws\.com$/; +// The regions AWS CodeCommit runs in. +const AWS_REGIONS = [ + "ap-southeast-1", + "ap-southeast-2", + "ap-southeast-3", + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + "ca-central-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "eu-central-1", + "eu-north-1", + "eu-south-1", + "sa-east-1", + "me-south-1", + "af-south-1", + "il-central-1", +]; + +function Step({ n, children }: { n: number; children: ReactNode }) { + return ( +
+ + {n} + +
{children}
+
+ ); +} + +function Code({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} + +type Key = NonNullable[number]; + +/** + * One kind of git host and the key it takes: no key → a Generate button; + * a key → step 1 (copy its public half) followed by the host's own steps. + */ +function KeyCard({ + title, + sub, + type, + k, + id, + busy, + onGenerate, + onRemove, + children, +}: { + title: string; + sub: string; + type: "ed25519" | "rsa"; + k: Key | undefined; + id: GitIdentity; + busy: boolean; + onGenerate: (type: "ed25519" | "rsa") => Promise; + onRemove: (type: "ed25519" | "rsa") => Promise; + children: ReactNode; +}) { + const { t } = useTranslation("settings"); + return ( +
+
+
+
{title}
+
{sub}
+
+ {id.writable && ( + + )} + {k && id.writable && ( + + )} +
+ {k ? ( + <> + +
+ {t("gitIdentity.stepCopy")} + +
+