mirror of
https://github.com/ruvnet/RuView
synced 2026-08-04 19:31:42 +00:00
f49c722764
The Rust port lived two directories deep (rust-port/wifi-densepose-rs/) without any sibling under rust-port/ that warranted the extra level. Move the whole workspace up to v2/ to match v1/ (Python) at the same depth and shorten every cd / build command across the repo. git mv preserves history for all tracked files. 60 files updated for path references (CI workflows, ADRs, docs, scripts, READMEs, internal .claude-flow state). Two manual fixes for relative-cd paths in CLAUDE.md and ADR-043 that became wrong after the depth change (cd ../.. → cd ..). Validated: - cargo check --workspace --no-default-features → clean (after target/ nuke; the gitignored target/ was carried by the OS rename and had hard-coded old paths in build scripts) - cargo test --workspace --no-default-features → 1,539 passed, 0 failed, 8 ignored (same totals as pre-rename) - ESP32-S3 on COM7 → still streaming live CSI (cb #40300, RSSI -64 dBm) After-merge follow-up: contributors should `rm -rf v2/target` once and let cargo regenerate from the new path.
92 lines
2.3 KiB
TypeScript
92 lines
2.3 KiB
TypeScript
import { useState, useEffect, useCallback, useRef } from "react";
|
|
import { invoke } from "@tauri-apps/api/core";
|
|
import type { Node } from "../types";
|
|
|
|
interface UseNodesOptions {
|
|
/** Auto-poll interval in milliseconds. Set to 0 to disable. Default: 10000 */
|
|
pollInterval?: number;
|
|
/** Whether to start scanning on mount. Default: false */
|
|
autoScan?: boolean;
|
|
}
|
|
|
|
interface UseNodesReturn {
|
|
nodes: Node[];
|
|
isScanning: boolean;
|
|
error: string | null;
|
|
scan: () => Promise<void>;
|
|
/** Total nodes discovered */
|
|
total: number;
|
|
/** Nodes currently online */
|
|
onlineCount: number;
|
|
/** Nodes currently offline */
|
|
offlineCount: number;
|
|
}
|
|
|
|
export function useNodes(options: UseNodesOptions = {}): UseNodesReturn {
|
|
const { pollInterval = 10_000, autoScan = false } = options;
|
|
|
|
const [nodes, setNodes] = useState<Node[]>([]);
|
|
const [isScanning, setIsScanning] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
|
|
const scan = useCallback(async () => {
|
|
if (isScanning) return;
|
|
setIsScanning(true);
|
|
setError(null);
|
|
|
|
try {
|
|
const discovered = await invoke<Node[]>("discover_nodes", {
|
|
timeoutMs: 5000,
|
|
});
|
|
setNodes(discovered);
|
|
} catch (err) {
|
|
const message =
|
|
err instanceof Error ? err.message : String(err);
|
|
setError(message);
|
|
} finally {
|
|
setIsScanning(false);
|
|
}
|
|
}, [isScanning]);
|
|
|
|
// Auto-scan on mount if requested
|
|
useEffect(() => {
|
|
if (autoScan) {
|
|
scan();
|
|
}
|
|
}, [autoScan]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
// Polling interval
|
|
useEffect(() => {
|
|
if (pollInterval <= 0) return;
|
|
|
|
intervalRef.current = setInterval(() => {
|
|
scan();
|
|
}, pollInterval);
|
|
|
|
return () => {
|
|
if (intervalRef.current) {
|
|
clearInterval(intervalRef.current);
|
|
intervalRef.current = null;
|
|
}
|
|
};
|
|
}, [pollInterval]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
|
|
const onlineCount = nodes.filter(
|
|
(n) => n.health === "online"
|
|
).length;
|
|
const offlineCount = nodes.filter(
|
|
(n) => n.health === "offline"
|
|
).length;
|
|
|
|
return {
|
|
nodes,
|
|
isScanning,
|
|
error,
|
|
scan,
|
|
total: nodes.length,
|
|
onlineCount,
|
|
offlineCount,
|
|
};
|
|
}
|