feat: add realtime pod activity streams
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import type { PodActivityEvent } from '@podman/shared';
|
||||
import { getPodActivity, podActivityStreamUrl } from '../lib/api';
|
||||
|
||||
export function usePodActivity(podId: string | null, me: string) {
|
||||
const [events, setEvents] = useState<PodActivityEvent[]>([]);
|
||||
const [connected, setConnected] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!podId) return;
|
||||
let alive = true;
|
||||
const load = async () => {
|
||||
try {
|
||||
const snapshot = await getPodActivity(podId);
|
||||
if (alive) {
|
||||
setEvents(snapshot);
|
||||
setError(null);
|
||||
}
|
||||
} catch (e) {
|
||||
if (alive) setError((e as Error).message);
|
||||
}
|
||||
};
|
||||
|
||||
void load();
|
||||
const source = new EventSource(podActivityStreamUrl(podId));
|
||||
source.addEventListener('open', () => {
|
||||
if (alive) setConnected(true);
|
||||
});
|
||||
source.addEventListener('snapshot', (event) => {
|
||||
if (!alive) return;
|
||||
setEvents(JSON.parse((event as MessageEvent<string>).data) as PodActivityEvent[]);
|
||||
setConnected(true);
|
||||
setError(null);
|
||||
});
|
||||
source.addEventListener('error', () => {
|
||||
if (alive) {
|
||||
setConnected(false);
|
||||
setError('Realtime activity stream reconnecting');
|
||||
}
|
||||
});
|
||||
|
||||
return () => {
|
||||
alive = false;
|
||||
source.close();
|
||||
};
|
||||
}, [podId]);
|
||||
|
||||
return useMemo(() => {
|
||||
const mine = events.filter((event) => belongsTo(event, me));
|
||||
const team = events.filter((event) => !belongsTo(event, me));
|
||||
return { events, mine, team, connected, error };
|
||||
}, [connected, error, events, me]);
|
||||
}
|
||||
|
||||
function belongsTo(event: PodActivityEvent, me: string): boolean {
|
||||
const normalized = me.trim().toLowerCase();
|
||||
if (!normalized) return false;
|
||||
const names = [event.actor, ...(event.actors ?? [])]
|
||||
.filter(Boolean)
|
||||
.map((name) => name!.trim().toLowerCase());
|
||||
return names.includes(normalized);
|
||||
}
|
||||
Reference in New Issue
Block a user