// Inter Instance Panel
// Purpose: Renders remote rover servers discovered through the inter-instance directory.
// Scope: Owns external server metadata presentation while reusing RoverQueuesPanel for rover/queue rows.
import { useMemo, useState } from 'react';
import { useSessionSelector } from '../../context/SessionContext.jsx';
import CardFrame from '../CardFrame/index.jsx';
import RoverQueuesPanel from '../RoverQueuesPanel/index.jsx';
import { openExternalRoverWithPrompt } from '../../lib/interInstanceTransfer.js';
import { isFeatureEnabled } from '../../lib/features.js';
function classNames(...values) {
return values.filter(Boolean).join(' ');
}
function useRemoteInstances() {
return useSessionSelector((state) => state.session?.interInstances?.instances ?? []);
}
function useInterInstanceEnabled() {
return useSessionSelector((state) => isFeatureEnabled(state, 'interInstance'));
}
function featureEntries(features = {}) {
return Object.entries(features || {})
.filter(([, enabled]) => Boolean(enabled))
.map(([name]) => name);
}
function InstanceStatus({ remote }) {
const mode = remote?.instance?.mode || 'unknown';
const online = Boolean(remote?.online);
return (
{online ? 'Online' : 'Offline'}
{mode}
{remote?.latencyMs != null ? (
{remote.latencyMs}ms
) : null}
);
}
function OfflineInstanceCard({ remote }) {
const name = remote?.instance?.name || remote?.url || 'External server';
return (
{remote?.url || 'No URL available.'}
{remote?.lastError ? {remote.lastError}
: null}
);
}
function InstanceMetadata({ remote }) {
const instance = remote?.instance || {};
const features = featureEntries(instance.features);
const color = instance.color || '#64748b';
return (
}
bodyClassName="space-y-0.5 p-0.5 text-sm"
>
{instance.description ?
{instance.description}
: null}
{instance.publicUrl ? {instance.publicUrl} : null}
{features.length ? (
{features.map((feature) => (
{feature}
))}
) : (
No advertised feature flags.
)}
);
}
function RemoteMediaStrip({ remote }) {
const roverSnapshots = (remote.roster || [])
.map((rover) => ({
id: rover.id,
name: rover.name || rover.id,
url: rover.snapshots?.latestUrl,
updatedAt: rover.snapshots?.updatedAt,
}))
.filter((entry) => entry.url);
const roomCameras = Array.isArray(remote.roomCameras) ? remote.roomCameras.filter((camera) => camera.snapshotUrl) : [];
const items = [
...roverSnapshots.map((entry) => ({ ...entry, kind: 'Rover' })),
...roomCameras.map((entry) => ({ ...entry, name: entry.name || entry.id, url: entry.snapshotUrl, kind: 'Room' })),
];
if (!items.length) return null;
return (
{items.map((item) => (
{item.name}
{item.kind}
))}
);
}
export function ExternalInstancesCompact() {
const [expanded, setExpanded] = useState(false);
const [popupOpen, setPopupOpen] = useState(false);
const enabled = useInterInstanceEnabled();
const instances = useRemoteInstances();
const visible = useMemo(() => instances.filter((remote) => remote?.online || remote?.url), [instances]);
if (!enabled) return null;
if (!visible.length) return null;
return (
{expanded ? (
{visible.map((remote) =>
remote.online ? (
) : (
),
)}
) : null}
{popupOpen ?
setPopupOpen(false)} /> : null}
);
}
export function InterInstancePopup({ onClose }) {
const enabled = useInterInstanceEnabled();
if (!enabled) return null;
return (
Close
}
className="w-full max-w-6xl"
bodyClassName="max-h-[82vh] overflow-y-auto p-0.5"
clipOverflow={false}
>
);
}
export default function InterInstancePanel({ compact = false, centered = false }) {
const enabled = useInterInstanceEnabled();
const instances = useRemoteInstances();
if (!enabled) return null;
if (compact) return ;
if (!instances.length) {
return (
No external instances discovered.
);
}
return (
{instances.map((remote) => (
{remote.online ? (
<>
>
) : (
)}
))}
);
}