fix(desktop): v0.4.1 - Fix Dashboard Quick Actions and Scan Network

- Add navigation to Quick Actions (Flash, OTA, WASM buttons now work)
- Add error feedback for Scan Network failures
- Create version.ts as single source of truth for version
- Switch reqwest from rustls-tls to native-tls for Windows compatibility
- Version bump to 0.4.1

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
Reuven 2026-03-09 23:46:29 -04:00
parent d3c683cc7e
commit 3b37aaf460
6 changed files with 57 additions and 37 deletions

View File

@ -2357,20 +2357,19 @@ dependencies = [
]
[[package]]
name = "hyper-rustls"
version = "0.27.7"
name = "hyper-tls"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
dependencies = [
"http",
"bytes",
"http-body-util",
"hyper",
"hyper-util",
"rustls 0.23.37",
"rustls-pki-types",
"native-tls",
"tokio",
"tokio-rustls",
"tokio-native-tls",
"tower-service",
"webpki-roots",
]
[[package]]
@ -4758,22 +4757,21 @@ dependencies = [
"http-body",
"http-body-util",
"hyper",
"hyper-rustls",
"hyper-tls",
"hyper-util",
"js-sys",
"log",
"mime_guess",
"native-tls",
"percent-encoding",
"pin-project-lite",
"quinn",
"rustls 0.23.37",
"rustls-pki-types",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"tokio",
"tokio-rustls",
"tokio-native-tls",
"tower",
"tower-http 0.6.8",
"tower-service",
@ -4781,7 +4779,6 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
"webpki-roots",
]
[[package]]
@ -6569,12 +6566,12 @@ dependencies = [
]
[[package]]
name = "tokio-rustls"
version = "0.26.4"
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"rustls 0.23.37",
"native-tls",
"tokio",
]
@ -7523,15 +7520,6 @@ dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webpki-roots"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
dependencies = [
"rustls-pki-types",
]
[[package]]
name = "webview2-com"
version = "0.38.2"

View File

@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json",
"productName": "RuView Desktop",
"version": "0.4.0",
"version": "0.4.1",
"identifier": "net.ruv.ruview",
"build": {
"frontendDist": "ui/dist",

View File

@ -1,7 +1,7 @@
{
"name": "ruview-desktop-ui",
"private": true,
"version": "0.4.0",
"version": "0.4.1",
"type": "module",
"scripts": {
"dev": "vite",

View File

@ -1,4 +1,5 @@
import { useState, useEffect, useCallback } from "react";
import { APP_VERSION } from "./version";
import Dashboard from "./pages/Dashboard";
import { Nodes } from "./pages/Nodes";
import NetworkDiscovery from "./pages/NetworkDiscovery";
@ -90,7 +91,7 @@ const App: React.FC = () => {
const renderPage = () => {
switch (activePage) {
case "dashboard": return <Dashboard />;
case "dashboard": return <Dashboard onNavigate={navigateTo} />;
case "discovery": return <NetworkDiscovery />;
case "nodes": return <Nodes />;
case "flash": return <FlashFirmware />;
@ -167,7 +168,7 @@ const App: React.FC = () => {
letterSpacing: "0.02em",
}}
>
v0.4.0
v{APP_VERSION}
</span>
</div>
</div>

View File

@ -19,19 +19,31 @@ interface ServerStatus {
ws_port: number | null;
}
const Dashboard: React.FC = () => {
type Page = "dashboard" | "discovery" | "nodes" | "flash" | "ota" | "wasm" | "sensing" | "mesh" | "settings";
interface DashboardProps {
onNavigate?: (page: Page) => void;
}
const Dashboard: React.FC<DashboardProps> = ({ onNavigate }) => {
const [nodes, setNodes] = useState<DiscoveredNode[]>([]);
const [serverStatus, setServerStatus] = useState<ServerStatus | null>(null);
const [scanning, setScanning] = useState(false);
const [scanError, setScanError] = useState<string | null>(null);
const handleScan = async () => {
setScanning(true);
setScanError(null);
try {
const { invoke } = await import("@tauri-apps/api/core");
const found = await invoke<DiscoveredNode[]>("discover_nodes", { timeoutMs: 3000 });
setNodes(found);
if (found.length === 0) {
setScanError("No nodes found. Ensure ESP32 devices are powered on and connected to the network.");
}
} catch (err) {
console.error("Discovery failed:", err);
setScanError(`Scan failed: ${err instanceof Error ? err.message : String(err)}`);
} finally {
setScanning(false);
}
@ -133,9 +145,9 @@ const Dashboard: React.FC = () => {
<div className="card">
<h3 className="heading-sm" style={{ marginBottom: "var(--space-3)" }}>Quick Actions</h3>
<div style={{ display: "flex", flexDirection: "column", gap: "var(--space-2)" }}>
<QuickAction label="Flash Firmware" desc="Flash via serial port" />
<QuickAction label="Push OTA Update" desc="Over-the-air to nodes" />
<QuickAction label="Upload WASM" desc="Deploy edge modules" />
<QuickAction label="Flash Firmware" desc="Flash via serial port" onClick={() => onNavigate?.("flash")} />
<QuickAction label="Push OTA Update" desc="Over-the-air to nodes" onClick={() => onNavigate?.("ota")} />
<QuickAction label="Upload WASM" desc="Deploy edge modules" onClick={() => onNavigate?.("wasm")} />
</div>
</div>
</div>
@ -145,7 +157,23 @@ const Dashboard: React.FC = () => {
<h3 className="heading-sm">Discovered Nodes ({nodes.length})</h3>
</div>
{nodes.length === 0 ? (
{scanError && (
<div
style={{
padding: "var(--space-3) var(--space-4)",
background: "rgba(248, 81, 73, 0.1)",
border: "1px solid rgba(248, 81, 73, 0.3)",
borderRadius: "var(--radius-md)",
marginBottom: "var(--space-4)",
fontSize: 13,
color: "var(--status-error)",
}}
>
{scanError}
</div>
)}
{nodes.length === 0 && !scanError ? (
<div className="card empty-state">
<div className="empty-state-icon">{"\u25C9"}</div>
<div style={{ fontSize: 14, fontWeight: 600, color: "var(--text-secondary)" }}>
@ -155,7 +183,7 @@ const Dashboard: React.FC = () => {
Click "Scan Network" to discover ESP32 devices on your local network.
</div>
</div>
) : (
) : nodes.length === 0 ? null : (
<div
style={{
display: "grid",
@ -258,9 +286,10 @@ function PortTag({ label, port }: { label: string; port: number }) {
);
}
function QuickAction({ label, desc }: { label: string; desc: string }) {
function QuickAction({ label, desc, onClick }: { label: string; desc: string; onClick?: () => void }) {
return (
<div
onClick={onClick}
style={{
display: "flex",
justifyContent: "space-between",

View File

@ -0,0 +1,2 @@
// Application version - single source of truth
export const APP_VERSION = "0.4.1";