Public dry run dryrun-309831e1e021
Source commit: 309831e1e021f962c118452336776fd9a94025f9 Public tree identity: sha256:6fa95c1745579bd6256dbeb3d476db0b07c2f24aa9213b0f7783ce1adfc8aca5
This commit is contained in:
commit
f22d0a5791
113 changed files with 39348 additions and 0 deletions
208
operator_panel_notes.md
Normal file
208
operator_panel_notes.md
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# Disasmer Operator Panel Notes
|
||||
|
||||
Disasmer programs should be able to expose a small human-facing UI through the coordinator web page.
|
||||
|
||||
This is useful for long-running build systems, repo watchers, task dashboards, and manual controls.
|
||||
|
||||
## Core idea
|
||||
|
||||
```text
|
||||
Disasmer program renders UI state
|
||||
Coordinator displays it in a webpage
|
||||
Human clicks/types/selects
|
||||
Coordinator sends typed events back to the program
|
||||
Program reacts by spawning, stopping, restarting, or debugging tasks
|
||||
```
|
||||
|
||||
The browser is only a view. The Disasmer program owns the state and logic.
|
||||
|
||||
## Terminology
|
||||
|
||||
```text
|
||||
Operator Panel
|
||||
A small immediate-mode UI exposed by a virtual process.
|
||||
|
||||
Widget
|
||||
A built-in UI element such as a button, textbox, dropdown, progress bar, or task table.
|
||||
|
||||
UI Event
|
||||
A typed event sent from the coordinator webpage back into the virtual process.
|
||||
```
|
||||
|
||||
## Example use case
|
||||
|
||||
A long-running build program can expose:
|
||||
|
||||
```text
|
||||
repo picker
|
||||
branch dropdown
|
||||
parallelism input
|
||||
start/stop buttons
|
||||
running task table
|
||||
progress bars
|
||||
log tail
|
||||
artifact links
|
||||
debug/restart/cancel buttons per task
|
||||
```
|
||||
|
||||
This makes the build system controllable without external YAML, dashboards, or proprietary CI UI.
|
||||
|
||||
## Rust sketch
|
||||
|
||||
```rust
|
||||
use disasmer::prelude::*;
|
||||
|
||||
#[disasmer::main]
|
||||
async fn main() -> Result<()> {
|
||||
let panel = ui::panel("Repo builder").await?;
|
||||
|
||||
let mut cfg = BuildConfig {
|
||||
repo: None,
|
||||
branch: "main".into(),
|
||||
parallelism: 4,
|
||||
};
|
||||
|
||||
let mut builds = BuildState::load().await?;
|
||||
|
||||
loop {
|
||||
let action = panel.draw(|ui| {
|
||||
ui.heading("Repo builder");
|
||||
|
||||
cfg.repo = ui.git_repo_picker("Repository", cfg.repo.clone());
|
||||
cfg.branch = ui.git_branch_dropdown("Branch", cfg.repo.as_ref(), &cfg.branch);
|
||||
cfg.parallelism = ui.number("Parallel builds", cfg.parallelism);
|
||||
|
||||
if ui.button("Start watcher").clicked() {
|
||||
ui.emit(Action::Start(cfg.clone()));
|
||||
}
|
||||
|
||||
if ui.button("Stop").clicked() {
|
||||
ui.emit(Action::Stop);
|
||||
}
|
||||
|
||||
ui.progress("Current build", builds.current_progress());
|
||||
ui.task_table("Running tasks", builds.running_tasks());
|
||||
ui.log_tail("Recent output", builds.log_stream());
|
||||
}).await?;
|
||||
|
||||
match action {
|
||||
Some(Action::Start(cfg)) => builds.start_watcher(cfg).await?,
|
||||
Some(Action::Stop) => builds.stop_watcher().await?,
|
||||
Some(Action::RestartTask(id)) => builds.restart_task(id).await?,
|
||||
Some(Action::CancelTask(id)) => builds.cancel_task(id).await?,
|
||||
None => {}
|
||||
}
|
||||
|
||||
builds.poll().await?;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## What this proves
|
||||
|
||||
A Disasmer build system can be expressed as one normal program containing:
|
||||
|
||||
```text
|
||||
build logic
|
||||
repo watching
|
||||
branch selection
|
||||
parallel task spawning
|
||||
human controls
|
||||
progress reporting
|
||||
logs
|
||||
artifact links
|
||||
debug hooks
|
||||
```
|
||||
|
||||
The build loop is just normal program logic. Build tasks are virtual threads.
|
||||
|
||||
## Task controls
|
||||
|
||||
A task table should support simple per-task actions:
|
||||
|
||||
```text
|
||||
Debug
|
||||
Restart
|
||||
Cancel
|
||||
View logs
|
||||
Open artifacts
|
||||
```
|
||||
|
||||
Example row:
|
||||
|
||||
```text
|
||||
commit abc123 | linux-x64 | running | 72% | Debug | Restart | Cancel
|
||||
```
|
||||
|
||||
## Debugging behavior
|
||||
|
||||
When the virtual process is running:
|
||||
|
||||
```text
|
||||
operator panel is interactive
|
||||
button clicks become UI events
|
||||
program handles events normally
|
||||
```
|
||||
|
||||
When the virtual process is stopped in a debugger:
|
||||
|
||||
```text
|
||||
panel shows last rendered state
|
||||
program-level UI events are disabled or queued
|
||||
control-plane actions may remain available
|
||||
```
|
||||
|
||||
For the MVP, prefer:
|
||||
|
||||
```text
|
||||
running process -> interactive panel
|
||||
stopped process -> read-only panel plus control-plane actions
|
||||
```
|
||||
|
||||
This avoids executing program code while the debugger says the process is stopped.
|
||||
|
||||
## MVP widget set
|
||||
|
||||
Start with:
|
||||
|
||||
```text
|
||||
text
|
||||
heading
|
||||
button
|
||||
textbox
|
||||
number input
|
||||
checkbox
|
||||
dropdown
|
||||
progress bar
|
||||
task table
|
||||
log tail
|
||||
artifact link
|
||||
git repo picker
|
||||
git branch picker
|
||||
```
|
||||
|
||||
Avoid initially:
|
||||
|
||||
```text
|
||||
custom HTML
|
||||
custom JavaScript
|
||||
complex layout
|
||||
live charts
|
||||
drag/drop workflow editors
|
||||
browser-side business logic
|
||||
```
|
||||
|
||||
## Design rule
|
||||
|
||||
The operator panel should stay boring, typed, and immediate-mode.
|
||||
|
||||
```text
|
||||
One source file can define:
|
||||
distributed execution
|
||||
build orchestration
|
||||
environment selection
|
||||
filesystem/artifact behavior
|
||||
debugging behavior
|
||||
human operator UI
|
||||
```
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue