import {Dropdown,Icon,type IconName} from '@nodedc/ui-react'; export type ObservationSourceModality='point-cloud'|'video'|'image'|'depth'; export type ObservationSourceAvailability='unverified'|'declared'|'available'|'connecting'|'streaming'|'degraded'|'unavailable'|'error'; export interface SpatialSourceDescriptor {id:string;label:string;modality:ObservationSourceModality;availability:ObservationSourceAvailability;endpointLabel?:string|null;transport:string;previewUrl?:string|null;delivery?:unknown;activation?:{controllable:boolean}|null} export const sourceIcon: Record = { "point-cloud": "globe", video: "video", image: "image", depth: "image", }; const availabilityCopy: Record = { unverified: "Не подтверждён", declared: "Канал объявлен", available: "Доступен", connecting: "Подключение", streaming: "Эфир", degraded: "Нестабильно", unavailable: "Недоступен", error: "Ошибка", }; export function observationSourceStatusLabel(source: SpatialSourceDescriptor): string { return availabilityCopy[source.availability]; } export function ObservationSourcePicker({ sources, visibleSourceIds, pendingSourceIds, onToggle, }: { sources: readonly SpatialSourceDescriptor[]; visibleSourceIds: ReadonlySet; pendingSourceIds?: ReadonlySet; onToggle: (sourceId: string) => void | Promise; }) { const visibleCount = sources.filter((source) => visibleSourceIds.has(source.id)).length; return ( ( )} >
НАБЛЮДЕНИЕ Источники данных
{sources.length ? `${visibleCount} из ${sources.length}` : "нет источников"}
{sources.length ? (
{sources.map((source) => { const selected = visibleSourceIds.has(source.id); const pending = pendingSourceIds?.has(source.id) ?? false; const canOpen = Boolean( selected || source.modality === "point-cloud" || source.previewUrl || source.delivery || source.activation?.controllable, ); return (