Skip to content

Rework GUI for first-run usability - #9

Merged
ihadeed merged 10 commits into
masterfrom
gui-ux
Jul 18, 2026
Merged

ihadeed merged 10 commits into
masterfrom
gui-ux

Conversation

@ihadeed

@ihadeed ihadeed commented Jul 18, 2026

Copy link
Copy Markdown
Member

Addresses hands-on feedback on the v2.1.1 desktop app.

  • Fix the blank window at launch: the app shell was not a renderable Fyne widget; now implemented properly, with a regression test that renders the real launch composition and fails if the window ever goes blank or nav labels clip again
  • Settings: network selection is now a dropdown of the machine's interfaces with friendly labels ("Wi-Fi (wlan0) — 192.168.1.23"), physical NICs ranked ahead of docker/bridge/VPN interfaces, an "Automatic (recommended)" default, and an "All networks" option (new additive wildcard-listen support in the library, Go 1.12-compatible with its own tests)
  • Simulator is a first-class area: open/create/edit a scenario, run and stop the simulated network in-app, simulated devices appear tagged in the Network Explorer for browsing and writes
  • New Home screen with two primary actions (Simulate a network / Discover my network); plain-language navigation, status bar, and error copy

Both modules pass gofmt, vet, and the race suite; rendered-output tests cover launch, nav, settings, and the simulate-to-explore flow.

ihadeed added 10 commits July 18, 2026 19:40
AppShell embedded *fyne.Container directly, which only satisfies
fyne.CanvasObject by method promotion; the driver's render-tree walk
only recognizes a concrete *fyne.Container or a fyne.Widget, so
window.SetContent(shell) painted nothing. Make AppShell a real widget
(widget.BaseWidget + CreateRenderer) so this class of bug can't recur.

The same anti-pattern was present in DiscoveryView, BrowserView,
EditorView, and QuickstartView, which meant every view's content was
invisible once nested inside AppShell's content stack even after the
shell itself rendered. Convert all four to proper widgets too.

Extract main()'s wiring into internal/boot.Compose, the single
composition root shared by main() and the new rendered regression
tests, which capture the composed window's canvas and assert on
painted pixels rather than the container tree.
Settings now offers "Automatic (recommended)" plus each usable network
interface by human-friendly label instead of a raw text field, backed
by a new netpick package. Bootstrap resolves Automatic to the best
real interface at start time, and Settings now restarts the live
session on save instead of requiring a relaunch, reporting plain
connected/failed status either way.
Adds Run/Stop controls and a running-devices strip to the scenario
editor, migrating the runner lifecycle from the deleted Quickstart view.
Run validates the document, serializes it via the editor's own
scenariodoc.Document, and starts it through simrun; a scenario simrun
can't run gets plain-language guidance instead of the raw error. "Load
example scenario" loads the bundled quickstart scenario into the editor
(confirming first if there are unsaved edits), so the old one-click demo
becomes Simulator -> Load example scenario -> Run.

Injected devices carry Source "simulated" and a Name, so Discovery can
tell them apart from real Who-Is sightings and show their name; the
DeviceStore merges Name the same way it already preserves Source across
re-sightings. Discovery gains a Name column and renders Source as
plain-language "Simulated"/"Network" text.

boot.go wires the shared DeviceStore into the Simulator view and a
PortHint callback so a running simulation's status includes a tip when
the current session port won't reach it.
Mounts the editor view into a real window/canvas and asserts the
strip actually occupies rendered space and paints content once a
simulation starts, catching the exact clipped/zero-size failure mode
that v.root.Refresh() in onRun/onStop guards against.
Home greets first-run users with two big actions (Simulate a network,
Discover my network) plus a Settings shortcut instead of a blank pane.
Nav trims to Home / Network Explorer / Simulator; Object Browser is now
a drill-down of Network Explorer with a Back-to-results button rather
than its own top-level row. Discovery gets plain-language copy (Scan
network, an empty-state placeholder) and a launch failure now reports
"Not connected yet" instead of a raw error.
getNetworkSet("") now returns the wildcard source (0.0.0.0) paired
with the limited broadcast address (255.255.255.255) instead of
failing, so a Server can bind and send on every network the OS
routes to rather than one named interface. Named interfaces are
unaffected.
Settings' Network dropdown gains "All networks" ahead of the
existing Automatic entry, persisting a "*" sentinel that
StartFromSettings maps to the bacnet library's new wildcard listen.
Automatic keeps the "(recommended)" wording since its directed
broadcast is more reliable on multi-homed hosts than All networks'
limited broadcast.
The nav List's item template was an empty-string label, so Fyne's
cached per-row min size collapsed the whole rail to near zero width
and long labels like "Network Explorer" rendered as "Net". Seed the
template with the widest actual nav label instead, and strengthen the
rendered-launch test to assert the nav rail and each rendered nav
label are at least as wide as their own MinSize.
Automatic picked the alphabetically first non-loopback interface, so
a docker/bridge/veth interface could beat the real LAN NIC. Mark
candidates matching common virtual-interface prefixes and rank them
after physical ones in both the sorted list and Automatic's pick,
without hiding them from the dropdown.
Replace raw "sweep failed:", "open failed:", "save failed:", and
"simulation start failed:" status text with plain sentences that
still include the underlying error as a short reason.
@ihadeed

ihadeed commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

Reviewed before merge (2 rounds): launch composition rendered and verified non-blank with legible navigation (regression-locked); interface ranking and Automatic selection unit-tested against synthetic interface lists; simulate-to-explore flow driven end-to-end; both modules race-clean. One residual minor (technical error strings on deep Object Browser surfaces) deferred to a follow-up.

@ihadeed
ihadeed merged commit 811944c into master Jul 18, 2026
17 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant