kanban-dev-webapp/src/components/card/commit-history.tsx
Dave 73f0f6e655 feat(dashboard): tag logged entries, hide fabricated raw detail in all three render paths
- Add "Logged" tag to manual entries in recent-activity feed
- Add "Logged" tag to manual entries in card commit history
- Hide raw technical detail block for manual entries (no diff exists)
- Replace short_sha code block with "Logged" tag in unassigned linking tray
- Fix screen-reader label to say "this logged entry" instead of "manual"
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-19 13:08:41 +02:00

93 lines
3.4 KiB
TypeScript

"use client";
import { useState } from "react";
import { Code2 } from "lucide-react";
import { relativeTime } from "@/lib/time/relative";
import type { CommitRecord } from "@/lib/pb/types";
/**
* A card's commits, in the client's language.
*
* Two rules, both from the spec:
* - A commit with no summary shows its raw subject. Never a gap — a card that
* renders blank because the provider was down looks like no work happened.
* - The raw commit is always one toggle away. The humanised text is a
* translation, not a replacement, and a client who wants to check it must be
* able to.
*/
export function CommitHistory({ commits }: { commits: CommitRecord[] }) {
const [showRaw, setShowRaw] = useState(false);
if (commits.length === 0) return null;
return (
<section className="space-y-3">
<div className="flex items-center gap-3">
<h2 className="text-xs font-semibold uppercase tracking-wide text-text-secondary">
Work done
</h2>
<span className="tabular text-xs text-text-muted">
{commits.length} {commits.length === 1 ? "change" : "changes"}
</span>
<button
type="button"
onClick={() => setShowRaw((value) => !value)}
aria-pressed={showRaw}
className="ml-auto inline-flex items-center gap-1.5 text-[11px] text-text-muted hover:text-text-secondary"
>
<Code2 size={12} strokeWidth={2} />
{showRaw ? "Hide technical detail" : "Show technical detail"}
</button>
</div>
<ol className="space-y-2.5">
{commits.map((commit) => (
<li key={commit.id} className="flex gap-2.5">
<span
aria-hidden
className="mt-[7px] h-1.5 w-1.5 shrink-0 rounded-full bg-border-strong"
/>
<div className="min-w-0 flex-1">
<div className="flex items-baseline gap-2">
<p className="text-sm text-text-secondary">
{/* Fall back to the raw subject — never render nothing. */}
{commit.summary || commit.subject}
</p>
{commit.source === "manual" && (
<span className="shrink-0 text-[10px] font-medium uppercase tracking-wide text-priority-medium">
Logged
</span>
)}
</div>
<p className="mt-0.5 text-[11px] text-text-muted">
{relativeTime(commit.authored_at)}
</p>
{/* No real diff or hash sits behind a logged entry — showing one
anyway, even honestly labelled, would be the fabrication this
feature deliberately avoids. */}
{showRaw && commit.source !== "manual" && (
<p className="mt-1.5 rounded bg-surface px-2 py-1.5 font-mono text-[11px] text-text-muted">
{commit.url ? (
<a
href={commit.url}
target="_blank"
rel="noreferrer"
className="hover:text-brand"
>
{commit.short_sha}
</a>
) : (
commit.short_sha
)}{" "}
{commit.subject}
</p>
)}
</div>
</li>
))}
</ol>
</section>
);
}