feat(ui): add download-all attachment action

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-08-19 12:08:34 +00:00
1 parent 2f302334f7
commit e250a31982
3 files changed
+43 -1

No files matched your search

@@ -116,6 +116,32 @@ describe("IssueAttachmentsSection", () => {
vi.unstubAllGlobals();
});
it("renders download-all beside upload with a direct archive link", async () => {
const attachment = makeAttachment();
await act(async () => {
root.render(
<QueryClientProvider client={queryClient}>
<IssueAttachmentsSection
attachments={[attachment]}
downloadAllHref="/api/issues/issue-1/attachments/archive"
uploadButton={<button type="button" aria-label="Upload attachment">Upload</button>}
onImageClick={vi.fn()}
/>
</QueryClientProvider>,
);
});
await flushReact();
const downloadAll = container.querySelector<HTMLAnchorElement>(
'a[aria-label="Download all attachments"]',
);
expect(downloadAll?.getAttribute("href")).toBe("/api/issues/issue-1/attachments/archive");
expect(downloadAll?.getAttribute("title")).toBe("Download all attachments");
expect(downloadAll?.getAttribute("target")).toBeNull();
expect(container.querySelector('button[aria-label="Upload attachment"]')).toBeTruthy();
});
it("renders markdown attachments with the document markdown presentation", async () => {
const attachment = makeAttachment({
id: "markdown-attachment",
+16 -1
View File
@@ -22,6 +22,7 @@ import { Card } from "@/components/ui/card";
interface IssueAttachmentsSectionProps {
attachments: IssueAttachment[];
downloadAllHref?: string;
uploadButton?: ReactNode;
error?: string | null;
dragActive?: boolean;
@@ -212,6 +213,7 @@ function GenericAttachmentRow({
export function IssueAttachmentsSection({
attachments,
downloadAllHref,
uploadButton,
error,
dragActive = false,
@@ -269,7 +271,20 @@ export function IssueAttachmentsSection({
<h3 className="text-sm font-medium text-muted-foreground">Attachments</h3>
<span className="text-xs text-muted-foreground">{attachments.length}</span>
</div>
{uploadButton}
<div className="flex items-center gap-1">
{downloadAllHref ? (
<Button asChild variant="ghost" size="icon-sm">
<a
href={downloadAllHref}
aria-label="Download all attachments"
title="Download all attachments"
>
<Download className="h-4 w-4" />
</a>
</Button>
) : null}
{uploadButton}
</div>
</div>
{error && (
+1
View File
@@ -5124,6 +5124,7 @@ export function IssueDetail() {
) : hasAttachments ? (
<IssueAttachmentsSection
attachments={attachmentList}
downloadAllHref={`/api/issues/${issue.id}/attachments/archive`}
uploadButton={attachmentUploadButton}
error={attachmentError}
dragActive={attachmentDragActive}