File size: 1,864 Bytes
5710dd0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | /**
* React binding for the session activity hub: one hub per (server, token),
* torn down on server switch or unmount. Consumers read per-session coarse
* activity (`get(sessionId)`) and re-render on every store bump; list-level
* signals invalidate the `['sessions']` / `['v2-sessions']` react-query lists
* directly.
*
* The hub is created inside `useEffect` (not `useMemo`): under StrictMode
* the mount → cleanup → re-mount cycle runs the cleanup of the FIRST mount,
* and a memo-created hub would stay closed for the rest of the page's life.
*/
import { useQueryClient } from '@tanstack/react-query';
import { useEffect, useState, useSyncExternalStore } from 'react';
import { useConnection } from '../connection';
import { SessionActivityHub, SessionActivityStore, type SessionWorkFacts } from './store';
const EMPTY_STORE = new SessionActivityStore();
export function useSessionActivities(): {
get(sessionId: string): SessionWorkFacts | undefined;
} {
const { baseUrl, config } = useConnection();
const queryClient = useQueryClient();
const token = config.token.trim();
const [hub, setHub] = useState<SessionActivityHub | null>(null);
useEffect(() => {
const created = new SessionActivityHub({
url: baseUrl,
token: token === '' ? undefined : token,
onListChanged: () => {
void queryClient.invalidateQueries({ queryKey: ['sessions'] });
void queryClient.invalidateQueries({ queryKey: ['v2-sessions'] });
void queryClient.invalidateQueries({ queryKey: ['workspaces'] });
},
});
setHub(created);
return () => {
setHub(null);
created.close();
};
}, [baseUrl, token, queryClient]);
const store = hub?.store ?? EMPTY_STORE;
useSyncExternalStore(
(listener) => store.subscribe(listener),
() => store.getVersion(),
);
return store;
}
|