Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member | 1 | /** |
| 2 | * Deleted workspaces, as the Deleted workspaces page shows them: what went | |
| 3 | * with each, how long is left to restore it, and what staff must type to | |
| 4 | * purge one now. No Workers imports, so it can be tested under Node. | |
| 5 | */ | |
| 6 | import type { WorkspaceDeletion } from "@g1t/contracts"; | |
| 7 | ||
| 8 | const plural = (n: number, one: string, many: string) => `${n} ${n === 1 ? one : many}`; | |
| 9 | ||
| 10 | /** What went with a workspace, in a line: "3 repositories, 1 project, 2 members". */ | |
| 11 | export function wentSummary(went: WorkspaceDeletion): string { | |
| 12 | const parts = [ | |
| 13 | plural(went.repositories, "repository", "repositories"), | |
| 14 | plural(went.projects, "project", "projects"), | |
| 15 | plural(went.members, "member", "members"), | |
| 16 | ]; | |
| 17 | return parts.join(", "); | |
| 18 | } | |
| 19 | ||
| 20 | /** Whole days left before `purgeAfter` (RFC 3339), from `now`; 0 once it is due. */ | |
| 21 | export function daysLeft(purgeAfter: string, now: number): number { | |
| 22 | const left = Date.parse(purgeAfter) - now; | |
| 23 | if (!Number.isFinite(left) || left <= 0) return 0; | |
| 24 | return Math.ceil(left / 86_400_000); | |
| 25 | } | |
| 26 | ||
| 27 | /** Whether what staff typed to purge a workspace now is its slug. Identity checks it again. */ | |
| 28 | export function confirmsPurge(slug: string, typed: string): boolean { | |
| 29 | return typed.trim().toLowerCase() === slug.toLowerCase(); | |
| 30 | } |