fix(attachments): link media to source memos

Close https://github.com/usememos/memos/issues/6120
This commit is contained in:
boojack 2026-07-29 09:06:42 +08:00
parent 6f1ff135fb
commit c4221c6dfe
3 changed files with 73 additions and 6 deletions

View file

@ -4,7 +4,7 @@ import { Badge } from "@/components/ui/badge";
import VideoPoster from "@/components/VideoPoster";
import type { AttachmentLibraryMediaItem, AttachmentLibraryMonthGroup } from "@/hooks/useAttachmentLibrary";
import { useTranslate } from "@/utils/i18n";
import { AttachmentMetadataLine, AttachmentOpenButton } from "./AttachmentLibraryPrimitives";
import { AttachmentMetadataLine, AttachmentOpenButton, AttachmentSourceChip } from "./AttachmentLibraryPrimitives";
interface AttachmentMediaGridProps {
groups: AttachmentLibraryMonthGroup[];
@ -60,12 +60,12 @@ const AttachmentMediaCard = ({ item, onPreview }: { item: AttachmentLibraryMedia
)}
</div>
<AttachmentMetadataLine
className="min-w-0"
items={[item.fileTypeLabel, item.createdLabel !== "—" ? item.createdLabel : undefined]}
/>
<div className="flex items-center justify-between gap-2">
<AttachmentMetadataLine
className="min-w-0 flex-1"
items={[item.fileTypeLabel, item.createdLabel !== "—" ? item.createdLabel : undefined]}
/>
<AttachmentSourceChip memoName={item.memoName} />
<AttachmentOpenButton href={item.sourceUrl} />
</div>
</div>

View file

@ -37,6 +37,7 @@ export interface AttachmentLibraryMediaItem extends AttachmentVisualItem {
createdAt?: Date;
createdLabel: string;
fileTypeLabel: string;
memoName?: string;
}
export interface AttachmentLibraryMonthGroup {
@ -96,6 +97,7 @@ const toLibraryMediaItem = (item: AttachmentVisualItem, locale: string, livePhot
createdAt,
createdLabel: formatCreatedAt(createdAt, locale),
fileTypeLabel: item.kind === "motion" ? livePhotoLabel : fileTypeLabel,
memoName: primaryAttachment.memo,
};
};

View file

@ -0,0 +1,65 @@
import { create } from "@bufbuild/protobuf";
import { fireEvent, render, screen } from "@testing-library/react";
import { MemoryRouter } from "react-router-dom";
import { describe, expect, it, vi } from "vitest";
import AttachmentMediaGrid from "@/components/AttachmentLibrary/AttachmentMediaGrid";
import type { AttachmentLibraryMonthGroup } from "@/hooks/useAttachmentLibrary";
import { AttachmentSchema } from "@/types/proto/api/v1/attachment_service_pb";
vi.mock("@/utils/i18n", () => ({ useTranslate: () => (key: string) => key }));
describe("<AttachmentMediaGrid>", () => {
it("links a media attachment to its source memo without replacing the direct file action", () => {
const attachment = create(AttachmentSchema, {
name: "attachments/photo",
filename: "photo.jpg",
type: "image/jpeg",
memo: "memos/source-memo",
});
const groups: AttachmentLibraryMonthGroup[] = [
{
key: "2026-07",
label: "Jul 2026",
items: [
{
id: attachment.name,
kind: "image",
filename: attachment.filename,
posterUrl: "/file/attachments/photo/photo.jpg?thumbnail=1",
sourceUrl: "/file/attachments/photo/photo.jpg",
attachmentNames: [attachment.name],
attachments: [attachment],
previewItem: {
id: attachment.name,
kind: "image",
filename: attachment.filename,
sourceUrl: "/file/attachments/photo/photo.jpg",
},
mimeType: attachment.type,
primaryAttachment: attachment,
createdLabel: "Jul 29, 2026",
fileTypeLabel: "JPEG",
memoName: attachment.memo,
},
],
},
];
const onPreview = vi.fn();
render(
<MemoryRouter>
<AttachmentMediaGrid groups={groups} onPreview={onPreview} />
</MemoryRouter>,
);
const memoLink = screen.getByRole("link", { name: "attachment-library.labels.memo" });
expect(memoLink).toHaveAttribute("href", "/memos/source-memo");
const fileLink = screen.getByRole("link", { name: "attachment-library.actions.open" });
expect(fileLink).toHaveAttribute("href", "/file/attachments/photo/photo.jpg");
expect(fileLink).toHaveAttribute("target", "_blank");
fireEvent.click(memoLink);
expect(onPreview).not.toHaveBeenCalled();
});
});