Add live git status indicators (#458)

This commit is contained in:
Gregory Schier
2026-05-08 11:25:39 -07:00
committed by GitHub
parent 1b154ba550
commit d7e67cf13c
35 changed files with 1702 additions and 578 deletions

View File

@@ -0,0 +1,38 @@
import { watchGitWorktreeStatus, type GitWorktreeStatusEntry } from "@yaakapp-internal/git";
import { activeWorkspaceMetaAtom } from "../hooks/useActiveWorkspace";
import { gitWorktreeStatusAtom, gitWorktreeStatusByModelIdAtom } from "../lib/gitWorktreeStatus";
import { jotaiStore } from "../lib/jotai";
export function initGit() {
let watchedDir: string | null = null;
let unwatch: null | ReturnType<typeof watchGitWorktreeStatus> = null;
const watchActiveWorkspace = () => {
const syncDir = jotaiStore.get(activeWorkspaceMetaAtom)?.settingSyncDir ?? null;
if (syncDir === watchedDir) return;
void unwatch?.();
unwatch = null;
watchedDir = syncDir;
jotaiStore.set(gitWorktreeStatusAtom, null);
jotaiStore.set(gitWorktreeStatusByModelIdAtom, {});
if (syncDir == null) return;
unwatch = watchGitWorktreeStatus(syncDir, (status) => {
if (syncDir !== watchedDir) return;
jotaiStore.set(gitWorktreeStatusAtom, status);
const statusByModelId: Record<string, GitWorktreeStatusEntry> = {};
for (const entry of status.entries) {
if (entry.modelId == null) continue;
statusByModelId[entry.modelId] = entry;
}
jotaiStore.set(gitWorktreeStatusByModelIdAtom, statusByModelId);
});
};
watchActiveWorkspace();
jotaiStore.sub(activeWorkspaceMetaAtom, watchActiveWorkspace);
}

View File

@@ -29,13 +29,45 @@ const debouncedSync = debounce(async () => {
await sync();
}, 1000);
let modelSyncTimer: ReturnType<typeof setTimeout> | null = null;
let modelSyncInFlight = false;
function scheduleModelSync() {
if (modelSyncTimer == null) {
// No timer means this is the first model change in a burst, so sync immediately.
void syncModelChanges();
} else {
// Keep pushing the trailing sync out until model writes have been quiet for a bit.
clearTimeout(modelSyncTimer);
}
modelSyncTimer = setTimeout(async () => {
modelSyncTimer = null;
// Catch any final state that was written while the immediate sync was running.
await syncModelChanges();
}, 1000);
}
async function syncModelChanges() {
if (modelSyncInFlight) return;
modelSyncInFlight = true;
try {
await sync();
} catch (e) {
console.error(e);
} finally {
modelSyncInFlight = false;
}
}
/**
* Subscribe to model change events. Since we check the workspace ID on sync, we can
* simply add long-lived subscribers for the lifetime of the app.
*/
function initModelListeners() {
listenToTauriEvent<ModelPayload>("model_write", (p) => {
if (isModelRelevant(p.payload.model)) debouncedSync();
if (isModelRelevant(p.payload.model)) scheduleModelSync();
});
}