import type { IssueAttachment } from "../../../../api/types.ts"; import { fmtStamp } from "../../board/model/util.ts"; import { Badge, Button, IconDownload, IconExternal, IconFile, IconImage, IconSheet } from "../../../../ui/index.ts"; import { fileKind, fmtSize, isTooBig, jiraAttachmentUrl, TOO_BIG_HINT } from "./format.ts"; import type { useAttachmentDownload } from "./useAttachmentDownload.ts"; import "./attachments.css"; export type Download = ReturnType; const KIND_ICON = { image: IconImage, sheet: IconSheet, pdf: IconFile, other: IconFile }; const KIND_LABEL = { image: "картинка", sheet: "таблица", pdf: "PDF", other: "файл" }; // новые сверху: по времени Jira, затем по числовому id export function newestFirst(items: IssueAttachment[]): IssueAttachment[] { const t = (a: IssueAttachment) => (a.created ? Date.parse(a.created) || 0 : 0); return [...items].sort((a, b) => t(b) - t(a) || (Number(b.attachment_id) || 0) - (Number(a.attachment_id) || 0)); } // раздел «Вложения (N)»: значок по типу, имя, размер, «автор · дата», отметка «у хаба», кнопка скачивания export function AttachmentList({ items, dl }: { items: IssueAttachment[]; dl: Download }) { return (

Вложения ({items.length})

); } function Row({ a, dl }: { a: IssueAttachment; dl: Download }) { const kind = fileKind(a.mime_type, a.filename); const Icon = KIND_ICON[kind]; const { busy, error: local } = dl.status(a.attachment_id); // ошибка: своя (последняя попытка в этой карточке) или команда, закончившаяся failed до открытия карточки const error = busy ? null : local ?? (a.state === "failed" ? a.error ?? "не удалось скачать вложение" : null); const who = [a.author, a.created ? fmtStamp(a.created) : null].filter(Boolean).join(" · "); return (
  • {a.filename} {fmtSize(a.size)}{who && ` · ${who}`} {a.state === "ready" && <>{" "}у хаба} {error &&

    {error}

    }
    {isTooBig(a.size) ? Открыть в Jira : }
  • ); }