import { useQueryClient } from "@tanstack/react-query"; import { toast } from "@unom/ui/toast"; import type { FC } from "react"; import { ApiError } from "@/api/fetcher"; import { getGetDisplayMonitorsQueryKey, getGetDisplaySettingsQueryKey, useGetDisplayMonitors, useGetDisplaySettings, useSetDisplaySettings, } from "@/api/gen/display/display"; import type { ApiMonitorInfo } from "@/api/gen/model"; import { QueryState } from "@/components/query-state"; import { Badge } from "@/components/ui/badge"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { cn } from "@/lib/utils"; import { m } from "@/paraglide/messages"; /** * **Streamed screen** (design/per-monitor-portal-capture.md §5.3): stream one of the host's real * monitors instead of creating a virtual display per client. * * Deliberately a HOST-wide choice, not per-client — it is the decision of record for this feature, * and it is also what keeps input honest: the injector is host-lifetime and shared by every * concurrent session, so "which screen do absolute coordinates land on" can only have one answer. * * Saves on selection (like the policy card above) — there is no Save button to miss. The pin is a * field of the display policy, so it rides the same PUT. */ export const MonitorCard: FC = () => { const qc = useQueryClient(); const monitors = useGetDisplayMonitors(); const settings = useGetDisplaySettings(); const save = useSetDisplaySettings(); const policy = settings.data?.settings; const rows = monitors.data?.monitors ?? []; // The host reports the EFFECTIVE pin — an env-pinned appliance shows its real answer here even // though the console cannot change it. const pinned = monitors.data?.pinned ?? null; // `PUNKTFUNK_CAPTURE_MONITOR` outranks the stored policy, so a host pinned in its unit's // environment is read-only here: offering controls that silently lose to the env would be worse // than saying so. // // Requires the policy to have LOADED: while `/display/settings` is in flight (or has failed) // `policy` is undefined, which is never equal to `pinned` — so the card used to announce an env // pin that may not exist and go read-only on every slow load. const envLocked = !!pinned && !!policy && policy.capture_monitor !== pinned; // The host says whether it can honor a pin at all. Windows enumerates its heads but has no // backend that can capture one (see `MonitorsResponse.pin_supported`), and this card used to // offer the choice anyway: the PUT persisted, nothing consumed it, and a virtual display was // still created on connect. Defaults to TRUE when the field is absent so an older host — which // only ever shipped this picker where it worked — is not retroactively locked out. const pinSupported = monitors.data?.pin_supported ?? true; // Both reasons produce the same read-only card; only the explanation above it differs. const locked = envLocked || !pinSupported; const choose = (connector: string | null) => { if (!policy || locked) return; save.mutate( { data: { ...policy, capture_monitor: connector } }, { onSuccess: () => { qc.invalidateQueries({ queryKey: getGetDisplaySettingsQueryKey() }); qc.invalidateQueries({ queryKey: getGetDisplayMonitorsQueryKey() }); toast.success(m.display_monitor_saved()); }, }, ); }; const busy = save.isPending; const error = save.error instanceof ApiError ? save.error.message : undefined; const row = ( key: string, selected: boolean, title: string, hint: string, tags?: ReturnType[], onSelect?: () => void, ) => ( ); const monitorRow = (mon: ApiMonitorInfo) => { const tags = [ mon.primary ? ( {m.display_monitor_primary()} ) : null, !mon.enabled ? ( {m.display_monitor_disabled()} ) : null, ].filter(Boolean) as ReturnType[]; return row( mon.connector, pinned?.toLowerCase() === mon.connector.toLowerCase(), `${mon.connector} — ${mon.description}`, `${mon.mode} · ${m.display_monitor_mirror_hint()}`, tags, // A disabled head cannot be streamed (the host refuses with that reason), so don't // offer it as a choice — it is listed so "why isn't it here?" has an answer. mon.enabled && !mon.managed ? () => choose(mon.connector) : undefined, ); }; return ( {m.display_monitor_title()}

{m.display_monitor_intro()}

{!pinSupported && (

{m.display_monitor_unsupported()}

)} {pinSupported && envLocked && (

{m.display_monitor_env_locked()}

)}
{row( "__virtual__", !pinned, m.display_monitor_virtual(), m.display_monitor_virtual_hint(), undefined, () => choose(null), )} {rows.map(monitorRow)} {rows.length === 0 && (

{monitors.data?.error ? m.display_monitor_unavailable() : m.display_monitor_none()}

)}
{error &&

{error}

}
); };