| 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 | } |