feat(web): add durable control-plane event updates

This commit is contained in:
chick
2026-07-17 18:31:07 +08:00
parent 6e817f380a
commit be1741c2f8
10 changed files with 745 additions and 4 deletions
+18 -1
View File
@@ -1,4 +1,8 @@
import type { ReactNode } from 'react';
import { useMemo } from 'react';
import { useControlPlaneEvents } from './events/use-control-plane-events.js';
import { createEventStreamClient, type EventStreamClient } from './events/event-stream-client.js';
import { FleetPage, type FleetDataSource, type FleetSnapshot } from './fleet/fleet-page.js';
import { createFleetApiDataSource } from './fleet/fleet-api-data-source.js';
@@ -57,6 +61,7 @@ export interface AppShellProps {
instanceDataSource?: InstanceDataSource;
capabilities?: InstanceCapabilityMap;
capabilityDataSource?: CapabilityDataSource;
eventStreamClient?: EventStreamClient;
}
const MODULE_LABELS = INSTANCE_MODULE_LABELS;
@@ -123,6 +128,7 @@ function Page({
instanceDataSource,
capabilities,
capabilityDataSource,
fleetRefreshSignal,
}: {
route: ResolvedRoute;
fleetDataSource: FleetDataSource | undefined;
@@ -131,12 +137,14 @@ function Page({
instanceDataSource: InstanceDataSource | undefined;
capabilities: InstanceCapabilityMap | undefined;
capabilityDataSource: CapabilityDataSource | undefined;
fleetRefreshSignal: number;
}): ReactNode {
if (route.kind === 'fleet')
return (
<FleetPage
{...(fleetDataSource ? { dataSource: fleetDataSource } : {})}
{...(fleetData ? { initialData: fleetData } : {})}
refreshSignal={fleetRefreshSignal}
/>
);
if (route.kind === 'instance-new')
@@ -201,9 +209,17 @@ export function AppShell({
instanceDataSource,
capabilities,
capabilityDataSource,
eventStreamClient,
}: AppShellProps) {
const defaultEventStreamClient = useMemo(() => createEventStreamClient(), []);
const defaultFleetDataSource = useMemo(() => createFleetApiDataSource(), []);
const resolved = resolveRoute(pathname);
const route = resolved.kind === 'redirect' ? resolveRoute(resolved.to ?? '/fleet') : resolved;
const routeInstanceId = route.params?.instanceId;
const refresh = useControlPlaneEvents(
routeInstanceId,
eventStreamClient ?? defaultEventStreamClient,
);
const currentSection = section(route);
return (
<div className="app-shell" data-route={route.kind}>
@@ -239,12 +255,13 @@ export function AppShell({
<main id="main-content" tabIndex={-1}>
<Page
route={route}
fleetDataSource={fleetDataSource ?? createFleetApiDataSource()}
fleetDataSource={fleetDataSource ?? defaultFleetDataSource}
fleetData={fleetData}
instance={instance}
instanceDataSource={instanceDataSource}
capabilities={capabilities}
capabilityDataSource={capabilityDataSource}
fleetRefreshSignal={refresh.fleet}
/>
</main>
</div>