| import { useMemo, useState } from "react" |
|
|
| import { Check, Copy, Terminal } from "lucide-react" |
|
|
| import { Button } from "@/components/ui/button" |
| import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" |
| import { buildUploadCommand } from "@/lib/submission-utils" |
|
|
| type UploadCommandPanelProps = { |
| presignedUrl: string |
| } |
|
|
| export function UploadCommandPanel({ |
| presignedUrl, |
| }: UploadCommandPanelProps) { |
| const [copied, setCopied] = useState<"url" | "command" | null>(null) |
|
|
| const uploadCommand = useMemo( |
| () => buildUploadCommand(presignedUrl), |
| [presignedUrl] |
| ) |
|
|
| async function handleCopy(value: string, kind: "url" | "command") { |
| await navigator.clipboard.writeText(value) |
| setCopied(kind) |
|
|
| window.setTimeout(() => { |
| setCopied((current) => (current === kind ? null : current)) |
| }, 1400) |
| } |
|
|
| return ( |
| <Card |
| size="sm" |
| className="min-w-0 max-w-full border-border bg-card text-card-foreground shadow-none" |
| > |
| <CardHeader className="gap-2"> |
| <CardTitle className="flex items-center gap-2 text-sm sm:text-base"> |
| <Terminal className="size-4" /> |
| Upload Docker image tar |
| </CardTitle> |
| <p className="text-sm text-muted-foreground"> |
| This pre-signed URL expires in 3 hours. Upload your image tar with |
| the generated command below. |
| </p> |
| </CardHeader> |
| <CardContent className="min-w-0 space-y-4"> |
| <div className="space-y-2"> |
| <div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center sm:justify-between"> |
| <p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground"> |
| Pre-signed URL |
| </p> |
| <Button |
| size="sm" |
| type="button" |
| variant="outline" |
| onClick={() => void handleCopy(presignedUrl, "url")} |
| > |
| {copied === "url" ? <Check className="size-4" /> : <Copy className="size-4" />} |
| {copied === "url" ? "Copied" : "Copy"} |
| </Button> |
| </div> |
| <pre className="max-w-full overflow-x-auto rounded-xl border border-border bg-muted/40 px-4 py-3 text-xs text-muted-foreground"> |
| <code>{presignedUrl}</code> |
| </pre> |
| </div> |
| <div className="space-y-2"> |
| <div className="flex flex-col items-start gap-2 sm:flex-row sm:items-center sm:justify-between"> |
| <p className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground"> |
| Shell command |
| </p> |
| <Button |
| size="sm" |
| type="button" |
| variant="outline" |
| onClick={() => void handleCopy(uploadCommand, "command")} |
| > |
| {copied === "command" ? ( |
| <Check className="size-4" /> |
| ) : ( |
| <Copy className="size-4" /> |
| )} |
| {copied === "command" ? "Copied" : "Copy"} |
| </Button> |
| </div> |
| <pre className="max-w-full overflow-x-auto rounded-xl border border-border bg-zinc-950 px-4 py-3 text-xs text-zinc-50"> |
| <code>{uploadCommand}</code> |
| </pre> |
| </div> |
| </CardContent> |
| </Card> |
| ) |
| } |
|
|