import type { DiffFile } from '../types';
import { ConfirmDialog } from './ConfirmDialog';
import { Icon } from './Icon';
// A diff the server refused to hand over unasked, because rendering it would
// wedge the page (see git.Repo.Diff). Two shapes, both built from the file
// summary that came back in its place:
//
// - OversizeWarning — the modal that asks, put up as soon as the diff lands.
// - OversizeNotice — what stands in for the diff afterwards, so a dismissed
// warning doesn't leave an empty screen with no way back.
//
// The size is nearly always a base ref whose history has moved on rather than a
// genuinely enormous review, so both of them point at the base and at what to
// switch to.
const n = (x: number) => x.toLocaleString();
// sizeLine describes the change set in one phrase: "412 files, 87,204 changed
// lines". Binary files count for no lines, so the file count carries them.
function sizeLine(files: DiffFile[]): string {
const lines = files.reduce((total, f) => total + f.additions + f.deletions, 0);
return `${n(files.length)} file${files.length === 1 ? '' : 's'}, ${n(lines)} changed line${
lines === 1 ? '' : 's'
}`;
}
// commitAdvice points at the other way through a change set too big to render:
// the commits are listed in the left rail whether or not the patch loaded, and
// one of them at a time costs nothing.
function commitAdvice(commits: number): string | null {
if (commits === 0) return null;
return (
'The commits it spans are listed in the left rail — reading one at a time ' +
'renders only that commit, however big the whole range is.'
);
}
// advice suggests the way out, which depends on what the base already is.
function advice(base: string, suggested: string): string {
if (base === 'HEAD') {
return 'That is a lot of uncommitted work for one screen.';
}
const alternative = suggested && suggested !== base ? `${suggested}, or HEAD` : 'HEAD';
return (
`A diff this size usually means ${base} has moved on since this work was ` +
`cut from it, so the change set is padded with commits nobody is reviewing. ` +
`Switching the base to ${alternative} will show only the work itself.`
);
}
export function OversizeWarning({
files,
base,
suggested,
commits,
onLoad,
onCancel,
}: {
files: DiffFile[];
base: string;
suggested: string;
commits: number;
onLoad: () => void;
onCancel: () => void;
}) {
return (
{advice(base, suggested)} {commitAdvice(commits)}{base} gives {sizeLine(files)}. Rendering
that much at once can leave the page unresponsive for a while.
{base} gives {sizeLine(files)} — enough to make the page
unresponsive, so it wasn’t rendered.
{advice(base, suggested)}
{commitAdvice(commits) &&{commitAdvice(commits)}
}