From 9756df67017fb09d088f93f7a541a05c019da4da Mon Sep 17 00:00:00 2001 From: Parker TenBroeck <51721964+ParkerTenBroeck@users.noreply.github.com> Date: Sat, 14 Mar 2026 10:38:37 -0400 Subject: [PATCH] added an indicator for compiling --- relay/src/main.rs | 1 + relay/src/uploaded.rs | 51 ++++++++++++++++++++++++++++++++++++++++-- relay/src/workspace.rs | 25 +++++++++++++++++++++ relay/ui/app.js | 30 ++++++++++++++++++++++--- relay/ui/styles.css | 6 +++++ 5 files changed, 108 insertions(+), 5 deletions(-) diff --git a/relay/src/main.rs b/relay/src/main.rs index ba44a60..d9bb3ca 100644 --- a/relay/src/main.rs +++ b/relay/src/main.rs @@ -184,6 +184,7 @@ pub enum ClientMsg { #[serde(rename_all = "snake_case")] pub enum ServerMsg<'a> { Log { stream: &'a str, line: &'a str }, + Compiling, Start, Stop, Led(u32), diff --git a/relay/src/uploaded.rs b/relay/src/uploaded.rs index 0571905..1a9ecc7 100644 --- a/relay/src/uploaded.rs +++ b/relay/src/uploaded.rs @@ -19,9 +19,24 @@ pub async fn ws_handler(socket: WebSocket, refresh_time: Duration) { return; }; + _ = sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Compiling) + .unwrap_or_default() + .into(), + )) + .await; + let temp_build = match build::copy_and_build(files).await { Ok(build) => build, Err(err) => { + _ = sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Stop) + .unwrap_or_default() + .into(), + )) + .await; _ = sender .send(Message::Text(format!("Failed to build: {err}").into())) .await; @@ -35,12 +50,26 @@ pub async fn ws_handler(socket: WebSocket, refresh_time: Duration) { let mut process = match run::run(&artifact_dir, &artifact).await { Ok(process) => process, Err(err) => { + _ = sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Stop) + .unwrap_or_default() + .into(), + )) + .await; _ = sender .send(Message::Text(format!("Failed to run: {err}").into())) .await; return; } }; + _ = sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Start) + .unwrap_or_default() + .into(), + )) + .await; let mut sout = BufReader::new(process.stdout).lines(); let mut serr = BufReader::new(process.stderr).lines(); @@ -80,7 +109,16 @@ pub async fn ws_handler(socket: WebSocket, refresh_time: Duration) { }; sender.send(Message::Text(serde_json::to_string(&msg)?.into())).await?; }, - Ok(None) => break, + Ok(None) => { + _ = sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Stop) + .unwrap_or_default() + .into(), + )) + .await; + break; + }, Err(err) => { Err(format!("Failed to read proccess sout: {err}"))?; } @@ -105,7 +143,16 @@ pub async fn ws_handler(socket: WebSocket, refresh_time: Duration) { }; sender.send(Message::Text(serde_json::to_string(&msg)?.into())).await?; }, - Ok(None) => break, + Ok(None) => { + _ = sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Stop) + .unwrap_or_default() + .into(), + )) + .await; + break; + }, Err(err) => { Err(format!("Failed to read proccess serr: {err}"))? } diff --git a/relay/src/workspace.rs b/relay/src/workspace.rs index e609f9d..c6f620c 100644 --- a/relay/src/workspace.rs +++ b/relay/src/workspace.rs @@ -197,9 +197,26 @@ impl Handler { } async fn run_program(&mut self) { + _ = self + .sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Compiling) + .unwrap_or_default() + .into(), + )) + .await; + let artifact = match build::build(&self.build_dir, &self.src_dir).await { Ok(artifact) => artifact, Err(err) => { + _ = self + .sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Stop) + .unwrap_or_default() + .into(), + )) + .await; _ = self.eprint(format!("Failed to build: {err}")).await; return; } @@ -208,6 +225,14 @@ impl Handler { let process = match run::run(&self.build_dir, &artifact).await { Ok(process) => process, Err(err) => { + _ = self + .sender + .send(Message::Text( + serde_json::to_string(&ServerMsg::Stop) + .unwrap_or_default() + .into(), + )) + .await; self.eprint(format!("Failed to run: {err}")).await; return; } diff --git a/relay/ui/app.js b/relay/ui/app.js index cda0a1e..72d99cb 100644 --- a/relay/ui/app.js +++ b/relay/ui/app.js @@ -693,6 +693,7 @@ class CircuitUiApp { this.config = config; this.dom = getDomRefs(); this.mode = config.initialMode; + this.isCompiling = false; this.isRunning = false; this.reconnectTimer = null; @@ -725,19 +726,26 @@ class CircuitUiApp { if (this.mode === "uploaded") { this.connection.send(this.editor.getFilesPayload()); } - this.connection.send({ input: this.inputs.getInputPayload() }); this.setRunButtonEnabled(true); this.updateStatusIndicator(); }, onMessage: (parsed, raw) => { + if (isUnitMessage(parsed, "compiling")) { + this.setCompiling(true); + return; + } + if (isUnitMessage(parsed, "start")) { this.logs.clear(); this.outputs.resetVisuals(); + this.setCompiling(false); this.setRunning(true); + this.connection.send({ input: this.inputs.getInputPayload() }); return; } if (isUnitMessage(parsed, "stop")) { + this.setCompiling(false); this.setRunning(false); return; } @@ -755,6 +763,7 @@ class CircuitUiApp { }, onClose: () => { this.setRunButtonEnabled(false); + this.setCompiling(false); this.setRunning(false); this.updateStatusIndicator(); if (this.mode === "workspace") { @@ -825,6 +834,14 @@ class CircuitUiApp { this.cancelReconnect(); } + this.setCompiling(false); + this.setRunning(false); + this.updateStatusIndicator(); + } + + setCompiling(compiling) { + this.isCompiling = Boolean(compiling); + this.dom.runToggleBtn.disabled = this.isCompiling || !this.connection.isConnected(); this.updateStatusIndicator(); } @@ -836,7 +853,7 @@ class CircuitUiApp { } setRunButtonEnabled(enabled) { - this.dom.runToggleBtn.disabled = !enabled; + this.dom.runToggleBtn.disabled = !enabled || this.isCompiling; this.updateStatusIndicator(); } @@ -860,9 +877,10 @@ class CircuitUiApp { updateStatusIndicator() { const pill = this.dom.statusPill; const connected = this.connection.isConnected(); + const compiling = connected && this.isCompiling; const running = connected && this.isRunning; - pill.classList.remove("state-disabled", "state-connected", "state-running"); + pill.classList.remove("state-disabled", "state-connected", "state-compiling", "state-running"); if (!connected) { pill.textContent = "DISABLED"; @@ -870,6 +888,12 @@ class CircuitUiApp { return; } + if (compiling) { + pill.textContent = "COMPILING"; + pill.classList.add("state-compiling"); + return; + } + if (running) { pill.textContent = "RUNNING"; pill.classList.add("state-running"); diff --git a/relay/ui/styles.css b/relay/ui/styles.css index 9d2183c..b10cbb0 100644 --- a/relay/ui/styles.css +++ b/relay/ui/styles.css @@ -213,6 +213,12 @@ textarea { background: color-mix(in srgb, var(--accent-muted) 72%, black 28%); } +.pill.state-compiling { + border-color: color-mix(in srgb, var(--warn) 70%, white 18%); + background: color-mix(in srgb, var(--warn) 24%, var(--surface-header) 76%); + box-shadow: 0 0 0 1px color-mix(in srgb, var(--warn) 32%, transparent); +} + .pill.state-running { border-color: var(--pill-connected-border); background: var(--pill-connected-bg);