Release 0.2.2 — browse submitted changelists, People & Roles, AI summaries

- History: GitHub-style split view of submitted changelists; preview file
  contents at their exact revision (code/image/3D/uasset) via `p4 print`
- People & Roles modal: who works on the depot, activity indicators,
  group/role assignment (p4 users / groups / group -i)
- AI commit summaries via OpenRouter (sparkle button); key/model in Settings
- Commit-message draft persists until Submit (not cleared on local commit)
- Resizable History file-list column (pointer-capture drag)
- Fix UI-scale leaving a gap at the bottom (compensate zoom in .win height)
- Author avatars on history rows; bump version to 0.2.2

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Bonchellon
2026-07-07 18:18:07 +03:00
parent 168b6afab3
commit 8e2cac4437
12 changed files with 613 additions and 46 deletions

View File

@ -22,9 +22,16 @@ export interface OpenedFile {
change?: string; // "default" or a number
user?: string;
client?: string;
_spec?: string; // when set, read this exact rev via `p4 print` (submitted/historical file)
[k: string]: unknown;
}
// choose the byte source: an exact submitted revision (`p4 print`) when `_spec`
// is set, otherwise the working copy (local file via `p4 where`).
export function fileBytes(f: OpenedFile): Promise<ArrayBuffer> {
return f._spec ? p4.printDepot(f._spec) : p4.readDepot(f.depotFile || "");
}
export interface Client {
client?: string;
Root?: string;
@ -86,9 +93,24 @@ export const p4 = {
if (Array.isArray(r)) return new Uint8Array(r as number[]).buffer;
return r as ArrayBuffer;
},
// read raw bytes at an exact revision (submitted/historical), e.g. "//depot/f.cpp#7"
printDepot: async (spec: string): Promise<ArrayBuffer> => {
const r: unknown = await invoke("print_depot", { spec });
if (r instanceof ArrayBuffer) return r;
if (ArrayBuffer.isView(r)) return (r as ArrayBufferView).buffer as ArrayBuffer;
if (Array.isArray(r)) return new Uint8Array(r as number[]).buffer;
return r as ArrayBuffer;
},
switchClient: (client: string) => invoke<P4Info>("p4_switch_client", { client }),
users: () => invoke<User[]>("p4_users"),
groups: (user = "") => invoke<{ group?: string }[]>("p4_groups", { user }),
groupMember: (group: string, user: string, add: boolean) => invoke<string>("p4_group_member", { group, user, add }),
readAiKey: () => invoke<string>("read_ai_key"),
saveAiKey: (key: string) => invoke<void>("save_ai_key", { key }),
};
export interface User { User?: string; Email?: string; FullName?: string; Access?: string; Update?: string; [k: string]: unknown }
export interface Dir { dir?: string; [k: string]: unknown }
// depot path -> short leaf name (last segment)
export function leaf(path?: string): string {