f6eb39eb73
- switch takes changes: carry (plain git switch, 409 ECARRYCONFLICT with files) or shelve (shelf first, re-applied if the switch fails) - branch-create switch: true runs git switch -c, the changes come along - shelve / unshelve / shelf-drop + GET /git/shelves: only agenthub-shelf: stash entries, addressed by sha, repo root only, never mid-operation; a clean restore drops the shelf, a conflicted one keeps it - 409 EAGENTRUNNING until confirm: true while the workspace's agent is working - git bar: Bring my changes / Shelve and switch choice, Create & switch, restore offer after a switch; Changes panel: Shelve (n) and the Shelves list - fix: after a switch the Changes panel showed the old branch — the post-write re-read joined an in-flight GET started before the write (request() dedupe); writes now close in-flight GETs, and every git write fires agenthub:git-changed so every view of the workspace re-reads
49 lines
1.8 KiB
TypeScript
49 lines
1.8 KiB
TypeScript
/**
|
|
* @file gitChanged.ts
|
|
* @description One window event, `agenthub:git-changed` `{laneId, action}`,
|
|
* fired after EVERY git write the dashboard sends for a workspace
|
|
* (`api.lanes.gitAction` fires it, success or failure — a failed shelve or
|
|
* a conflicted restore still moved files). Every view that shows that
|
|
* workspace's git state — the Changes panel of each repo, the header's facts
|
|
* (`useLaneGitFacts`, the rail counts included), the workspace home's branch —
|
|
* listens and reads again, so a switch made in one of them is never left
|
|
* stale in another for a poll interval. The views do not share a callback;
|
|
* this is the bus between them.
|
|
* @author Nguyễn Ngọc Trí Vĩ <vinnt@smartgift.vn>
|
|
*/
|
|
|
|
import { useEffect, useRef } from "react";
|
|
|
|
export const GIT_CHANGED_EVENT = "agenthub:git-changed";
|
|
|
|
export interface GitChangedDetail {
|
|
laneId: number;
|
|
/** The git action that ran (`switch`, `commit`, `shelve`, …). */
|
|
action: string;
|
|
}
|
|
|
|
/** Tell every view of `laneId` that its git state may have moved. */
|
|
export function emitGitChanged(laneId: number, action: string): void {
|
|
if (typeof window === "undefined") return;
|
|
window.dispatchEvent(
|
|
new CustomEvent<GitChangedDetail>(GIT_CHANGED_EVENT, { detail: { laneId, action } })
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Call `fn` after every git write on workspace `laneId`. The latest `fn` is
|
|
* used, so a caller may pass an inline closure without resubscribing.
|
|
*/
|
|
export function useGitChanged(laneId: number, fn: (action: string) => void): void {
|
|
const latest = useRef(fn);
|
|
latest.current = fn;
|
|
useEffect(() => {
|
|
const on = (e: Event) => {
|
|
const d = (e as CustomEvent<GitChangedDetail>).detail;
|
|
if (d && d.laneId === laneId) latest.current(d.action);
|
|
};
|
|
window.addEventListener(GIT_CHANGED_EVENT, on);
|
|
return () => window.removeEventListener(GIT_CHANGED_EVENT, on);
|
|
}, [laneId]);
|
|
}
|