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:
parent
d3c683cc7e
commit
3b37aaf460
|
|
@ -2357,20 +2357,19 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-tls"
|
||||||
version = "0.27.7"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58"
|
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"bytes",
|
||||||
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls 0.23.37",
|
"native-tls",
|
||||||
"rustls-pki-types",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-native-tls",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"webpki-roots",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4758,22 +4757,21 @@ dependencies = [
|
||||||
"http-body",
|
"http-body",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-rustls",
|
"hyper-tls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"mime_guess",
|
"mime_guess",
|
||||||
|
"native-tls",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"quinn",
|
|
||||||
"rustls 0.23.37",
|
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-native-tls",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http 0.6.8",
|
"tower-http 0.6.8",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
|
|
@ -4781,7 +4779,6 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
"webpki-roots",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -6569,12 +6566,12 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-native-tls"
|
||||||
version = "0.26.4"
|
version = "0.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls 0.23.37",
|
"native-tls",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -7523,15 +7520,6 @@ dependencies = [
|
||||||
"rustls-pki-types",
|
"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]]
|
[[package]]
|
||||||
name = "webview2-com"
|
name = "webview2-com"
|
||||||
version = "0.38.2"
|
version = "0.38.2"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json",
|
"$schema": "https://raw.githubusercontent.com/tauri-apps/tauri/dev/crates/tauri-config-schema/schema.json",
|
||||||
"productName": "RuView Desktop",
|
"productName": "RuView Desktop",
|
||||||
"version": "0.4.0",
|
"version": "0.4.1",
|
||||||
"identifier": "net.ruv.ruview",
|
"identifier": "net.ruv.ruview",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "ui/dist",
|
"frontendDist": "ui/dist",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "ruview-desktop-ui",
|
"name": "ruview-desktop-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.4.0",
|
"version": "0.4.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { useState, useEffect, useCallback } from "react";
|
import { useState, useEffect, useCallback } from "react";
|
||||||
|
import { APP_VERSION } from "./version";
|
||||||
import Dashboard from "./pages/Dashboard";
|
import Dashboard from "./pages/Dashboard";
|
||||||
import { Nodes } from "./pages/Nodes";
|
import { Nodes } from "./pages/Nodes";
|
||||||
import NetworkDiscovery from "./pages/NetworkDiscovery";
|
import NetworkDiscovery from "./pages/NetworkDiscovery";
|
||||||
|
|
@ -90,7 +91,7 @@ const App: React.FC = () => {
|
||||||
|
|
||||||
const renderPage = () => {
|
const renderPage = () => {
|
||||||
switch (activePage) {
|
switch (activePage) {
|
||||||
case "dashboard": return <Dashboard />;
|
case "dashboard": return <Dashboard onNavigate={navigateTo} />;
|
||||||
case "discovery": return <NetworkDiscovery />;
|
case "discovery": return <NetworkDiscovery />;
|
||||||
case "nodes": return <Nodes />;
|
case "nodes": return <Nodes />;
|
||||||
case "flash": return <FlashFirmware />;
|
case "flash": return <FlashFirmware />;
|
||||||
|
|
@ -167,7 +168,7 @@ const App: React.FC = () => {
|
||||||
letterSpacing: "0.02em",
|
letterSpacing: "0.02em",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
v0.4.0
|
v{APP_VERSION}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -19,19 +19,31 @@ interface ServerStatus {
|
||||||
ws_port: number | null;
|
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 [nodes, setNodes] = useState<DiscoveredNode[]>([]);
|
||||||
const [serverStatus, setServerStatus] = useState<ServerStatus | null>(null);
|
const [serverStatus, setServerStatus] = useState<ServerStatus | null>(null);
|
||||||
const [scanning, setScanning] = useState(false);
|
const [scanning, setScanning] = useState(false);
|
||||||
|
const [scanError, setScanError] = useState<string | null>(null);
|
||||||
|
|
||||||
const handleScan = async () => {
|
const handleScan = async () => {
|
||||||
setScanning(true);
|
setScanning(true);
|
||||||
|
setScanError(null);
|
||||||
try {
|
try {
|
||||||
const { invoke } = await import("@tauri-apps/api/core");
|
const { invoke } = await import("@tauri-apps/api/core");
|
||||||
const found = await invoke<DiscoveredNode[]>("discover_nodes", { timeoutMs: 3000 });
|
const found = await invoke<DiscoveredNode[]>("discover_nodes", { timeoutMs: 3000 });
|
||||||
setNodes(found);
|
setNodes(found);
|
||||||
|
if (found.length === 0) {
|
||||||
|
setScanError("No nodes found. Ensure ESP32 devices are powered on and connected to the network.");
|
||||||
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Discovery failed:", err);
|
console.error("Discovery failed:", err);
|
||||||
|
setScanError(`Scan failed: ${err instanceof Error ? err.message : String(err)}`);
|
||||||
} finally {
|
} finally {
|
||||||
setScanning(false);
|
setScanning(false);
|
||||||
}
|
}
|
||||||
|
|
@ -133,9 +145,9 @@ const Dashboard: React.FC = () => {
|
||||||
<div className="card">
|
<div className="card">
|
||||||
<h3 className="heading-sm" style={{ marginBottom: "var(--space-3)" }}>Quick Actions</h3>
|
<h3 className="heading-sm" style={{ marginBottom: "var(--space-3)" }}>Quick Actions</h3>
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: "var(--space-2)" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: "var(--space-2)" }}>
|
||||||
<QuickAction label="Flash Firmware" desc="Flash via serial port" />
|
<QuickAction label="Flash Firmware" desc="Flash via serial port" onClick={() => onNavigate?.("flash")} />
|
||||||
<QuickAction label="Push OTA Update" desc="Over-the-air to nodes" />
|
<QuickAction label="Push OTA Update" desc="Over-the-air to nodes" onClick={() => onNavigate?.("ota")} />
|
||||||
<QuickAction label="Upload WASM" desc="Deploy edge modules" />
|
<QuickAction label="Upload WASM" desc="Deploy edge modules" onClick={() => onNavigate?.("wasm")} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -145,7 +157,23 @@ const Dashboard: React.FC = () => {
|
||||||
<h3 className="heading-sm">Discovered Nodes ({nodes.length})</h3>
|
<h3 className="heading-sm">Discovered Nodes ({nodes.length})</h3>
|
||||||
</div>
|
</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="card empty-state">
|
||||||
<div className="empty-state-icon">{"\u25C9"}</div>
|
<div className="empty-state-icon">{"\u25C9"}</div>
|
||||||
<div style={{ fontSize: 14, fontWeight: 600, color: "var(--text-secondary)" }}>
|
<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.
|
Click "Scan Network" to discover ESP32 devices on your local network.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : nodes.length === 0 ? null : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "grid",
|
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
|
onClick={onClick}
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// Application version - single source of truth
|
||||||
|
export const APP_VERSION = "0.4.1";
|
||||||
Loading…
Reference in New Issue