mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-30 13:20:54 +01:00
Copy-only sweep across ui/src: nav (sidebar + mobile), Tasks list page (headings, breadcrumbs, buttons, empty states, filters, column headers, toasts, aria-labels), task detail, dialogs, command palette, inbox, search, dashboards, project/agent/workspace pages, recovery/blocked notices, and design-guide demos. Routes stay at /issues; internal symbols (Issue, issueId, queryKeys, kind: "issue"), API fields, and backend-matched protocol strings (successful-run-handoff notice bodies) are unchanged. Tests updated to match the new copy. Developer-only *UxLab/*Perf harness pages left as-is. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-Authored-By: Paperclip <noreply@paperclip.ing>
56 lines
2.3 KiB
TypeScript
56 lines
2.3 KiB
TypeScript
import { Play } from "lucide-react";
|
|
import type { IssueWorkProduct } from "@paperclipai/shared";
|
|
import { getIssueOutputs, type IssueOutputItem } from "@/lib/issue-output";
|
|
import { OutputPrimaryCard } from "./OutputPrimaryCard";
|
|
import { OutputRow } from "./OutputRow";
|
|
|
|
interface IssueOutputSectionProps {
|
|
workProducts: IssueWorkProduct[] | null | undefined;
|
|
/** Optional resolver for the artifact creator's display name. */
|
|
resolveCreatorName?: (item: IssueOutputItem) => string | null;
|
|
}
|
|
|
|
/**
|
|
* Issue Output surface (PAP-10162 Phase 3).
|
|
*
|
|
* Renders attachment-backed artifact work products as first-class issue
|
|
* outputs: a full-width primary card (video player / image / generic file) with
|
|
* Open + Download, plus compact rows for any additional outputs. The section is
|
|
* omitted entirely when the issue has produced no outputs — we never show a
|
|
* permanent empty card.
|
|
*/
|
|
export function IssueOutputSection({ workProducts, resolveCreatorName }: IssueOutputSectionProps) {
|
|
const { primary, rest, count } = getIssueOutputs(workProducts);
|
|
|
|
if (!primary) return null;
|
|
|
|
const creatorFor = (item: IssueOutputItem) => resolveCreatorName?.(item) ?? null;
|
|
|
|
return (
|
|
<section className="space-y-3" aria-label="Task outputs">
|
|
<div className="flex items-center gap-2">
|
|
<Play className="h-3.5 w-3.5 text-muted-foreground" aria-hidden="true" />
|
|
<h3 className="text-sm font-medium text-muted-foreground">Output</h3>
|
|
<span className="text-xs text-muted-foreground">{count}</span>
|
|
</div>
|
|
|
|
{/* Stable anchor target so company Artifacts cards can deep-link to a
|
|
specific work product inside its issue context (PAP-10359). */}
|
|
<div id={`work-product-${primary.id}`} className="scroll-mt-20">
|
|
<OutputPrimaryCard item={primary} creatorName={creatorFor(primary)} />
|
|
</div>
|
|
|
|
{rest.length > 0 && (
|
|
<div className="space-y-2">
|
|
<p className="text-[11px] font-medium uppercase tracking-wide text-muted-foreground">Also produced</p>
|
|
{rest.map((item) => (
|
|
<div key={item.id} id={`work-product-${item.id}`} className="scroll-mt-20">
|
|
<OutputRow item={item} creatorName={creatorFor(item)} />
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</section>
|
|
);
|
|
}
|