import type {ComponentType,ReactNode} from 'react'; import type {IconName} from '@nodedc/ui-react'; import type {Sensor, SensorTransport} from './contracts'; import type {EnrollmentTransport} from './enrollment'; import type {RerunHostFactory} from './rerunHost'; export interface SensorDetailProps { device:Sensor; transport:SensorTransport; enabled:boolean; back:()=>void; refresh:()=>Promise; failure:(error:unknown)=>void; createRerunHost?:RerunHostFactory; reconnect?:()=>void; } export interface SensorEnrollmentProps { transport:EnrollmentTransport; onClose:()=>void; onChange:()=>void; onComplete:(sessionId:string,signal?:AbortSignal)=>Promise; renderWindow:(view:{content:ReactNode;actions?:ReactNode;busy?:boolean})=>ReactNode; } export interface SensorUiContribution { kind:string; Detail:ComponentType; icon:IconName; retainOffline:boolean; supportsPreparation:boolean; supportsRenaming?:boolean; status?:(device:Sensor,fresh:boolean)=>{label:string;tone:'neutral'|'success'|'warning'|'danger'}; wirelessEnrollment?:{label:string;View:ComponentType}; } export function wirelessContributions(contributions:readonly SensorUiContribution[]):SensorUiContribution[] { return contributions.filter(value=>value.wirelessEnrollment&&contributions.filter(other=>other.kind===value.kind).length===1); } export function sensorContribution( contributions:readonly SensorUiContribution[], device:Sensor, ):SensorUiContribution|undefined { const matches=contributions.filter(value=>value.kind===device.kind); // An ambiguous renderer must not acquire authority over a device. return matches.length===1?matches[0]:undefined; }