Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

45 linesCodeBlameRaw
1/**
2 * `useHomeLive`: Home refreshing itself as the workspace moves
3 * (lib/home-live.ts says what it shows), and `useArrived`: which rows of
4 * a list on it are new, so they come in rather than appear.
5 *
6 * Besides its projects' changes, Home refreshes when the inbox moves or a
7 * notification for this workspace arrives: Where you're needed reads them.
8 */
9import { useEffect, useRef } from "react";
10
11import { HOME_GAP_MS, type HomeRepo, type Seen, arrivedOf, homeShows } from "./home-live";
12import { useNotifyState } from "./notify-client";
13import { useLive } from "./use-repo-live";
14
15export function useHomeLive(slug: string, repos: readonly HomeRepo[]): boolean {
16 const { live, nudge } = useLive({ repos, signedIn: true, match: (change) => homeShows(change, repos), gap: HOME_GAP_MS });
17
18 const { inbox, recent } = useNotifyState();
19 const newest = recent.find((n) => n.workspace.toLowerCase() === slug)?.id ?? null;
20 const before = useRef<{ inbox: number | null; newest: string | null } | null>(null);
21 useEffect(() => {
22 const was = before.current;
23 before.current = { inbox, newest };
24 // The first the feed says is where the page started, not a change.
25 if (was && ((was.inbox != null && inbox !== was.inbox) || newest !== was.newest)) nudge();
26 }, [inbox, newest, nudge]);
27
28 return live;
29}
30
31/**
32 * The keys of a list's rows that were not on it when it last drew: none
33 * on the first draw, nor right after `scope` (the span) changes. The same
34 * keys again give the same answer, so a row keeps its entrance for as
35 * long as it plays.
36 */
37export function useArrived(keys: readonly string[], scope = ""): ReadonlySet<string> {
38 const last = useRef<{ seen: Seen | null; id: string; arrived: ReadonlySet<string> }>({ seen: null, id: "", arrived: new Set() });
39 const id = `${scope}\n${keys.join("\n")}`;
40 if (last.current.seen == null || id !== last.current.id) {
41 const next = arrivedOf(last.current.seen, scope, keys);
42 last.current = { seen: next.seen, id, arrived: next.arrived };
43 }
44 return last.current.arrived;
45}