Files
backnotprop__plannotator/packages/review-editor/components/GeneratedFileNotice.tsx
Michael Ramos 15f8d4fe4c feat(review): collapse generated files by default in the all-files view (#1346)
* feat(review): collapse linguist-generated files by default (#1317)

Code review now respects linguist-generated (and linguist-generated=true)
from .gitattributes, collapsing those diffs by default the way GitHub does.

Server (Bun + Pi mirror): a generatedFiles sidecar rides /api/diff and
/api/diff/switch, resolved through git's own attribute machinery — one
batched 'git check-attr --stdin -z' over the served patch's paths at the
review cwd, so stacked and negated rules land exactly as git resolves
them. Plain local git sessions only; PR worktrees, workspace multi-repo,
jj, GitButler, and P4 omit the sidecar (degrade to no-collapse). Shared
logic in packages/shared/generated-files.ts, vendored to Pi.

Client: generated files SEED their CodeView item collapsed (the existing
Pierre collapse state — same mechanism as commit-diff folding), render
the one-line FileHeader bar with a 'generated' tag next to the +/- counts,
and expand per file on click. Expansion is session-local App state so it
survives remounts and diff switches. Presentation-only: the diff data,
annotations, search, and Edit Mode are untouched; the file tree and
single-file tabs list generated files normally (tag, no auto-collapse).

Guide viewer manifest pin regenerated (AllFilesCodeView/FileHeader are
bundled into the guides.show viewer) from a clean frozen-lockfile install.

* feat(review): built-in generated defaults, visible collapsed strip, review-round fixes (#1317)

Round 2 on PR #1346, per maintainer review.

Built-in generated defaults (industry-standard two-layer detection):
packages/shared/generated-files.ts (vendored to Pi) now carries
DEFAULT_GENERATED_PATTERNS — lockfiles (package-lock.json, yarn.lock,
bun.lock, Cargo.lock, go.sum, ...) plus *.min.js / *.min.css / *.map —
matched against the path's last segment only. Explicit .gitattributes wins
in BOTH directions: linguist-generated (set/true) marks any file,
-linguist-generated / =false un-marks even a built-in name, unspecified
falls through to the defaults. In plain local git sessions check-attr
refines the defaults; the non-git degrade modes (piped patches, PR
worktrees, workspace, jj, GitButler, P4) now emit the sidecar from the
name-based defaults alone instead of omitting it.

Visible collapsed state: a collapsed generated card no longer renders as a
bare header — a GeneratedFileNotice strip ('Generated file collapsed',
+N/-N, 'Click to view') styled like the other below-header notices sits in
the card, and clicking it expands through the SAME reportFileCollapsed
funnel as the chevron.

Review findings:
- F1: search-match and sidebar-comment navigation expanded items without
  reporting through the funnel, so those expansions died on diff switch.
  Both now call syncAllCollapsedMirror + reportFileCollapsed; the funnel
  invariant comment lists the navigation-driven sites.
- F2: the check-attr call gets the same 5000ms timeout as review-core's
  stdin git callers, and Pi's vcs.ts stdin write gets the one-line EPIPE
  guard (call-flow.ts shape) a timeout kill makes reachable.
- F3: removed the dead prevGeneratedRef + collectSetDelta leg — a changed
  generated set always remounts via fileSetKey, so the delta path was
  unreachable.

Tests: default-list matching (glob + directory-named-bun.lock), both-
direction precedence, non-git sidecar from defaults (dual-runtime), the
placeholder strip through the funnel, and search expansion surviving a
re-seed round-trip. AGENTS.md payload docs updated. Guide viewer manifest
pin regenerated from this clean frozen-lockfile worktree.
2026-08-17 23:32:29 -07:00

52 lines
2.0 KiB
TypeScript

import React, { useLayoutEffect } from 'react';
/**
* What a collapsed generated file's card shows instead of an empty body
* (#1317). A default-collapsed lockfile would otherwise render as a bare
* file header, indistinguishable from a failed render — this strip states
* the fold is intentional, carries the +/- counts, and expands on click
* through the same collapse-report funnel as the header chevron.
*
* Styled like the other below-header notices (OversizedFileNotice,
* BinaryFileNotice): muted strip, existing tokens only.
*/
export const GeneratedFileNotice: React.FC<{
additions: number;
deletions: number;
/** Expand the file — the SAME toggle path the chevron uses, so the
* expansion reports through reportFileCollapsed and survives remounts. */
onExpand: () => void;
/** Re-measure hook for the virtualized all-files host (custom-header portal
* heights are not auto-observed). */
onHeightChange?: () => void;
}> = ({ additions, deletions, onExpand, onHeightChange }) => {
// Layout effect (before paint) so the host re-measures without a one-frame
// overlap with the content below.
useLayoutEffect(() => {
onHeightChange?.();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return (
<button
type="button"
data-pn-generated-collapsed-notice=""
onClick={(e) => {
e.stopPropagation();
onExpand();
}}
className="flex w-full items-center gap-2 px-4 py-2 text-left text-xs leading-relaxed text-muted-foreground border-b border-border bg-muted/30 hover:bg-muted/60 transition-colors cursor-pointer"
title="Expand diff"
>
<span>Generated file collapsed</span>
<span className="flex items-center gap-1.5 font-mono">
{additions > 0 && <span className="text-success">+{additions}</span>}
{deletions > 0 && <span className="text-destructive">-{deletions}</span>}
</span>
<span className="ml-auto underline decoration-dotted underline-offset-2">
Click to view
</span>
</button>
);
};