MCPcopy
hub / github.com/cpaczek/skylight / Control

Function Control

web/src/control/Control.tsx:32–589  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

30};
31
32export function Control() {
33 const { state, conn } = useStream("control");
34 const cfg = state.config;
35
36 // Location editor (Nominatim via the server's /api/geocode).
37 const [geoBusy, setGeoBusy] = useState(false);
38 const [geoErr, setGeoErr] = useState<string | null>(null);
39
40 // Airport runway import (OurAirports via the server's /api/airport).
41 const [apBusy, setApBusy] = useState(false);
42 const [apErr, setApErr] = useState<string | null>(null);
43
44 // ISS pass finder (for the Sky section).
45 const [tles, setTles] = useState<Tle[]>([]);
46 useEffect(() => {
47 let on = true;
48 fetch("/api/tle")
49 .then((r) => (r.ok ? r.json() : []))
50 .then((t) => on && setTles(t as Tle[]))
51 .catch(() => {});
52 return () => {
53 on = false;
54 };
55 }, []);
56 const nextPass = useMemo(
57 () => (tles.length && cfg ? nextISSPass(Date.now(), cfg.centerLat, cfg.centerLon, tles) : null),
58 [tles, cfg?.centerLat, cfg?.centerLon],
59 );
60
61 if (!cfg) {
62 return (
63 <div className="loading">
64 <div className={`dot ${state.connected ? "ok" : "bad"}`} />
65 {state.connected ? "Loading config…" : "Connecting to tracker…"}
66 </div>
67 );
68 }
69
70 const set = (patch: Partial<Config>) => conn.patchConfig(patch);
71 const setField = (k: keyof ShowFields, v: boolean) =>
72 conn.patchConfig({ showFields: { ...cfg.showFields, [k]: v } });
73 const statusMessage = state.status?.message ? ` · ${state.status.message}` : "";
74
75 const changeLocation = async (q: string) => {
76 if (!q.trim()) return;
77 setGeoBusy(true);
78 setGeoErr(null);
79 try {
80 const r = await fetch(`/api/geocode?q=${encodeURIComponent(q)}`);
81 if (!r.ok) {
82 setGeoErr(r.status === 404 ? `No match for “${q}”` : "Lookup failed");
83 return;
84 }
85 const hit = (await r.json()) as { lat: number; lon: number; name: string };
86 set({ centerLat: hit.lat, centerLon: hit.lon, locationName: hit.name });
87 } catch {
88 setGeoErr("Lookup failed");
89 } finally {

Callers

nothing calls this directly

Calls 12

useStreamFunction · 0.85
nextISSPassFunction · 0.85
labelLinesFunction · 0.85
formatLatLonFunction · 0.85
atCurrentFunction · 0.85
switchToProfileFunction · 0.85
removeProfileFunction · 0.85
setFunction · 0.85
setFieldFunction · 0.85
skyTimeLabelFunction · 0.85
fmtInFunction · 0.85
resetConfigMethod · 0.80

Tested by

no test coverage detected