Files
playpen/web/src/types.ts
T

133 lines
4.4 KiB
TypeScript

// Mirrors the JSON the review server produces — see src/review/model.zig, whose
// field names are the wire format.
//
// There is no repository in here to choose between: a review pane is bound to one
// work tree, and the tab's path is what names it. Everything below describes that
// one review.
export type Side = 'old' | 'new';
export type Author = 'user' | 'claude';
export type Status = 'draft' | 'submitted' | 'resolved';
export type Level = 'line' | 'file' | 'review';
// DraftTarget is what an in-progress (unsent) comment is anchored to.
export type DraftTarget =
| {
level: 'line';
file: string;
side: Side;
startLine: number;
endLine: number;
changeKey: string; // key of the end line, where the composer renders
}
| { level: 'file'; file: string }
| { level: 'review' };
export interface Reply {
id: string;
author: Author;
body: string;
createdAt: string;
}
export interface DiffContext {
base: string;
uncommitted: boolean;
// The sha of one commit out of the range, when the view is narrowed to it: the
// diff is then that commit alone, and `uncommitted` no longer applies. Absent
// for the whole change set, which is what a review opens on.
//
// Part of the context rather than a display preference beside it, because a
// line number only means something inside one revision — line 40 as one commit
// left it isn't line 40 at the tip of the branch — so a comment written here
// must not be placed on the full diff's lines.
commit?: string;
}
// Commit is one entry in the list of commits a diff spans, as the left rail shows
// them. `files`/`additions`/`deletions` are what the commit changed on its own,
// and are 0 for a merge, whose diff git doesn't summarize.
export interface Commit {
sha: string;
shortSha: string;
author: string;
date: string;
subject: string;
files: number;
additions: number;
deletions: number;
}
export interface Comment {
id: string;
level: Level;
file: string;
side: Side;
line: number;
endLine: number;
body: string;
author: Author;
status: Status;
replies: Reply[];
context: DiffContext;
createdAt: string;
updatedAt: string;
}
export interface RepoInfo {
path: string;
branch: string;
branches: string[];
refs: string[];
// The ref the base picker offers directly under HEAD, which a review opens on:
// the release branch, or main, depending on the repo. Decided server-side (see
// git.suggestedBase) so the rule lives in one place. Empty when there's nothing
// worth suggesting.
suggestedBase: string;
}
// What GET api/repo answers with for a tab that has a review open: the
// repository, plus the comment counts and the diff selection the server has on
// record.
export interface RepoState extends RepoInfo {
drafts: number;
openComments: number;
// The selection this tab last published (see api.setContext). Absent until the
// page publishes one. The browser is the source of truth for what's on screen;
// this copy is what lets an agent review, and anchor comments to, the same diff.
context?: DiffContext | null;
// Whether this machine has an Android Studio for the file headers to open
// files in (see api.openInStudio).
studio: boolean;
}
export interface DiffFile {
oldPath: string;
newPath: string;
status: string;
additions: number;
deletions: number;
}
export interface DiffPayload {
context: DiffContext;
patch: string;
files: DiffFile[];
// The commits the change set is made of, oldest first — the whole range, even
// when `context.commit` narrows the patch to one of them, so the list you
// picked from is still there to pick again. Filled in for an oversized diff
// too, where choosing a single commit is the fastest way to something readable.
commits: Commit[] | null;
// The range holds more commits than `commits` lists (the newest are kept).
moreCommits?: boolean;
// The change set is past what the UI can render, so the server withheld the
// patch. `files` is still filled in, so the size can be described before
// anything asks for it again with force. See git.Repo.Diff.
oversized?: boolean;
// A digest of what this selection resolved to when the patch was made. The
// page holds on to it and asks the server for the current one on a timer, so
// it can say the diff has been overtaken instead of reloading it mid-read.
// Empty when the patch was withheld — nothing on screen to go stale.
revision?: string;
}