| 1 | import type { EnvironmentId } from "@t3tools/contracts"; |
| 2 | |
| 3 | export type ReadyAttachmentUpload = { |
| 4 | readonly status: "ready"; |
| 5 | readonly environmentId: EnvironmentId; |
| 6 | readonly attachmentId: string; |
| 7 | }; |
| 8 | |
| 9 | export type AttachmentUploadState = |
| 10 | | { |
| 11 | readonly status: "uploading"; |
| 12 | readonly environmentId: EnvironmentId; |
| 13 | readonly progress: number; |
| 14 | readonly previous?: ReadyAttachmentUpload; |
| 15 | } |
| 16 | | ReadyAttachmentUpload |
| 17 | | { |
| 18 | readonly status: "failed"; |
| 19 | readonly environmentId: EnvironmentId; |
| 20 | readonly reason: string; |
| 21 | /** |
| 22 | * A pending upload the queue minted for this failed attempt. Retry and |
| 23 | * release delete it, so it must never carry a draft's persisted |
| 24 | * attachment id. |
| 25 | */ |
| 26 | readonly attachmentId?: string; |
| 27 | readonly previous?: ReadyAttachmentUpload; |
| 28 | }; |
| 29 | |
| 30 | export function attachmentUploadBlockReason(input: { |
| 31 | readonly imageIds: ReadonlyArray<string>; |
| 32 | readonly uploadsByImageId: Readonly<Record<string, AttachmentUploadState>>; |
| 33 | readonly environmentId: EnvironmentId; |
| 34 | }): string | null { |
| 35 | let pending = 0; |
| 36 | let failed = 0; |
| 37 | |
| 38 | for (const imageId of input.imageIds) { |
| 39 | const upload = input.uploadsByImageId[imageId]; |
| 40 | if (upload?.status === "failed" && upload.environmentId === input.environmentId) { |
| 41 | failed += 1; |
| 42 | } else if (upload?.status !== "ready" || upload.environmentId !== input.environmentId) { |
| 43 | pending += 1; |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | if (failed > 0) { |
| 48 | return failed === 1 |
| 49 | ? "Retry or remove the failed attachment" |
| 50 | : "Retry or remove the failed attachments"; |
| 51 | } |
| 52 | if (pending > 0) { |
| 53 | return pending === 1 ? "Attachment still uploading" : "Attachments still uploading"; |
| 54 | } |
| 55 | return null; |
| 56 | } |
| 57 | |
| 58 | export function formatAttachmentUploadProgress(progress: number): string { |
| 59 | const bounded = Math.max(0, Math.min(1, Number.isFinite(progress) ? progress : 0)); |
| 60 | return `${Math.floor(bounded * 100)}%`; |
| 61 | } |