g1t/apps/web/app/lib/access.ts
| 1 | import { type Abilities, type Capability, type RepoRole, needs } from "@g1t/contracts"; |
| 2 | |
| 3 | /** |
| 4 | * What the viewer may do in the repository being looked at, as the |
| 5 | * repository's layout loads it for its pages and the sidebar. |
| 6 | */ |
| 7 | export type ViewerAccess = { |
| 8 | /** Their effective role; null when they cannot see it. */ |
| 9 | role: RepoRole | null; |
| 10 | /** Whether they have a role of their own, not only because it is public. */ |
| 11 | insider: boolean; |
| 12 | can: Abilities; |
| 13 | }; |
| 14 | |
| 15 | /** The title of something the viewer cannot use, saying which role it needs; undefined when they can. */ |
| 16 | export function whyNot(can: Abilities | null | undefined, capability: Capability): string | undefined { |
| 17 | return can?.[capability] ? undefined : needs(capability); |
| 18 | } |
| 19 | |
| 20 | /** Whether the viewer sees the repository's settings: Maintain and up. */ |
| 21 | export function seesSettings(access: Pick<ViewerAccess, "can" | "insider"> | null | undefined): boolean { |
| 22 | return Boolean(access?.insider && (access.can.manage_settings || access.can.manage_protection)); |
| 23 | } |
| 24 | |
| 25 | /** Each settings page and the capability that opens it. */ |
| 26 | export const SETTINGS_CAPABILITY: Record<string, Capability> = { |
| 27 | "": "manage_settings", |
| 28 | repository: "manage_settings", |
| 29 | agents: "manage_settings", |
| 30 | branches: "manage_protection", |
| 31 | guardrails: "manage_protection", |
| 32 | webhooks: "manage_integrations", |
| 33 | secrets: "manage_integrations", |
| 34 | runners: "manage_integrations", |
| 35 | deployments: "manage_integrations", |
| 36 | domains: "manage_integrations", |
| 37 | dependencies: "manage_settings", |
| 38 | // Write and up can see who has access; Admins change it. |
| 39 | access: "push", |
| 40 | }; |