Files
EJClaw/apps/dashboard/src/RoomAttachmentGallery.tsx
Eyejoker 6197e90c8c Fix structured attachment rendering (#69)
* review: harden readonly git checks and lint verification

* test: satisfy readonly reviewer sandbox typing

* test: fix readonly reviewer sandbox assertions

* test: remove impossible readonly sandbox guards

* test: relax readonly sandbox assertions

* test: cast readonly sandbox expectation shape

* test: cast readonly sandbox expectation through unknown

* Phase 0 — STEP_DONE/TASK_DONE split + owner-follow-up integration smoke

* Add STEP_DONE guards, verdict storage, and stale delivery suppression

* style: format paired stepdone telemetry files

* Route STEP_DONE through reviewer

* Add structured Discord attachments

* style: format structured attachment test

* Fix room thread bot output parity

* Remove duplicate work item attachment migration from owner branch

* Remove legacy dashboard rooms renderer

* Extract dashboard parsed body renderer

* Extract dashboard redaction helpers

* Extract dashboard RoomCardV2 component

* Include RoomCardV2 test in vitest suite

* Extract dashboard RoomBoardV2 component

* Extract dashboard EmptyState component

* Extract dashboard InboxPanel component

* Split dashboard InboxPanel card renderer

* Extract dashboard TaskPanel component

* Extract dashboard UsagePanel component

* Fix dashboard room thread chunk rendering

* Extract dashboard ServicePanel component

* Render dashboard live progress markdown

* Extract dashboard SettingsPanel component

* Fix structured attachment rendering
2026-04-28 17:36:11 +09:00

39 lines
1.1 KiB
TypeScript

import type { RoomThreadEntry } from './roomThread';
type RoomAttachment = NonNullable<RoomThreadEntry['attachments']>[number];
function attachmentDisplayName(attachment: RoomAttachment): string {
if (attachment.name) return attachment.name;
const segments = attachment.path.split(/[\\/]/);
return segments.at(-1) || 'attachment';
}
function attachmentUrl(attachment: RoomAttachment): string {
return `/api/attachments?path=${encodeURIComponent(attachment.path)}`;
}
export function RoomAttachmentGallery({
attachments,
}: {
attachments?: RoomThreadEntry['attachments'];
}) {
if (!attachments || attachments.length === 0) return null;
return (
<ul className="room-attachments">
{attachments.map((attachment) => {
const name = attachmentDisplayName(attachment);
const url = attachmentUrl(attachment);
return (
<li className="room-attachment" key={`${attachment.path}:${name}`}>
<a href={url} rel="noreferrer" target="_blank">
<img alt={name} loading="lazy" src={url} />
<span>{name}</span>
</a>
</li>
);
})}
</ul>
);
}