Hero OS — Dioxus Bootstrap Migration: Status & Merge Plan #28

Open
opened 2026-03-16 16:41:07 +00:00 by mik-tf · 0 comments
Owner

Summary

Complete migration of Hero OS from Bootstrap/Askama server-rendered templates + JavaScript to pure Dioxus WASM using dioxus-bootstrap-css. Zero iframes, zero JavaScript, zero custom CSS overriding Bootstrap. Single WASM binary, offline-first, type-safe.

Status: Component conversion COMPLETE. Awaiting merge with development_mik_6_1 before final merge to development.

Continues from home#26 (original migration plan).

Live demo: https://herodevbootstrap.gent04.grid.tf


What Was Achieved

100% Pure dioxus-bootstrap-css

All 16 service UIs and 44 archipelago islands (60 UI crates total) now use dioxus-bootstrap-css components exclusively:

  • 572+ raw Bootstrap HTML patterns converted to typed Rust components
  • ~665 lines of Bootstrap-overriding custom CSS removed and replaced with Bootstrap utility classes on component props
  • Zero raw <div class="btn/card/alert/table/row/col/badge/spinner"> patterns remaining
  • Zero custom CSS that reimplements Bootstrap — remaining CSS is genuinely app-specific (animations, split panes, syntax highlighting, log viewers)

Components Used Throughout

Component Replaces
Button { color, outline, size, href, target, download } <button class="btn"> and <a class="btn" href>
Card { header_class, body_class, header, body, footer } <div class="card"> with sub-divs
Alert { color, dismissible, on_dismiss } <div class="alert">
Table { size, bordered, hover, responsive } <table class="table"> + <div class="table-responsive">
Row { } / Col { xs, sm, md, lg, xl } <div class="row"> / <div class="col-*">
Container { fluid } <div class="container">
Badge { color, pill } <span class="badge">
Spinner { size, color } <div class="spinner-border">
Nav { tabs, pills, vertical } + NavItem + NavLink <ul class="nav">
Navbar { expand, brand } <nav class="navbar">
TabList { active, tabs } <ul class="nav-tabs"> + <div class="tab-content">
Modal { } <div class="modal">
Toast { show, color, on_dismiss } + ToastContainer <div class="toast">
Breadcrumb + BreadcrumbItem <nav class="breadcrumb">
ListGroup + ListGroupItem <ul class="list-group">
InputGroup <div class="input-group">
Progress / ProgressBar <div class="progress">
Accordion + AccordionItem <div class="accordion">

dioxus-bootstrap-css Improvements (0.2.1 → 0.2.5)

We own the library and improved it during this migration:

Version Feature
0.2.2 Button { href } — renders <a> for link-buttons
0.2.3 Button { target, download } — complete anchor attribute support
0.2.4 Alert { on_dismiss } — callback for external state management
0.2.5 Toast headerless close button (Bootstrap 5.3 d-flex pattern) + on_dismiss

Shell Fixes (hero_os)

  • .desktop bottom gap: 112px → 130px (prevents dock overlap with window content)
  • Consistent py-3 top padding on all service UIs for proper spacing in hero_os windows
  • overflow: auto on island content wrapper divs (enables scrolling)

Technical Approach

The Gold Standard Pattern

Every service UI follows this pattern (proven with the Embedder test example):

Navbar { expand: NavbarExpand::Lg, class: "bg-body-tertiary border-bottom", brand: rsx! { ... } }
Container { fluid: true, class: "py-4",
    Row { class: "g-3",
        Col { lg: ColumnSize::Span(3),
            Card {
                class: "mb-3",
                header_class: "d-flex justify-content-between align-items-center py-2",
                body_class: "py-2",
                header: rsx! { span { class: "small", ... } },
                body: rsx! {
                    Table { size: Size::Sm, borderless: true, class: "mb-0 small", ... }
                },
            }
        }
        Col { lg: ColumnSize::Span(9),
            TabList { active: active_tab, tabs: vec![...] }
        }
    }
}

Key principles:

  • Bootstrap utility classes (small, py-2, btn-sm, form-control-sm) instead of custom CSS font-size overrides
  • Component props (header_class, body_class, responsive: true) instead of wrapper divs
  • No custom CSS for anything Bootstrap provides — remaining CSS is only for app-specific patterns

Branches and PRs

All work is on development_dioxus_bootstrap branches. DO NOT MERGE — see merge plan below.

hero_os + hero_archipelagos (branch: development_dioxus_bootstrap_2)

Repo PR
hero_os #27
hero_archipelagos #38

15 Service UIs (branch: development_dioxus_bootstrap)

Repo PR
hero_auth #7
hero_redis #14
hero_embedder #11
hero_indexer_ui #3
hero_aibroker #26
hero_services (includes hero_shrimp) #54
hero_compute (was hero_cloud) #18
hero_voice #7
hero_proxy #3
hero_inspector #6
hero_foundry #11
hero_books #82
hero_osis #13
hero_foundry_ui (was hero_forge_ui) #6
zinit #60

Merge Plan

Our development_dioxus_bootstrap branches were forked from development. Meanwhile, development_mik_6_1 has newer UI improvements (hero_compute nicer UI, foundry rename, etc.) not yet merged to development. This is what runs on herodev2.

Steps

  1. Merge development_mik_6_1 into development across all repos — brings herodev2's latest UI to the base branch
  2. Merge development INTO development_dioxus_bootstrap branches (not the other way) — preserves our work while pulling in new UI changes
  3. Resolve merge conflicts — our converted files vs their updated files
  4. Convert any new/changed UI from development_mik_6_1 to pure dioxus-bootstrap (same proven patterns)
  5. Test on herodevbootstrap — verify everything works
  6. Merge development_dioxus_bootstrap PRs into development — the final merge

Why merge (not rebase)

  • Preserves full history of both lines of work
  • Creates clear merge commits showing where they joined
  • No risk of losing commits from rewriting history

Expected conflict areas

  • app.rs files (both branches modified)
  • Navbar components (renames in mik_6_1, conversions in bootstrap)
  • CSS files (we cleaned them, they may have added new rules)
  • Cargo.toml (dependency versions)

What Remains After Merge

After steps 1-4, any new UI code from development_mik_6_1 needs the same dioxus-bootstrap conversion. This should be straightforward — we've established the exact patterns for every Bootstrap component type. The conversion is mechanical.


Progress Log

  • Phase 1-4: 16 service UIs converted from raw HTML to dioxus-bootstrap-css components (572+ patterns)
  • Phase 5: 44 archipelago islands converted
  • Shell fixes: Desktop bottom gap, top padding, scroll overflow
  • dioxus-bootstrap-css: Published 0.2.2 → 0.2.5 (Button href/target/download, Alert on_dismiss, Toast headerless)
  • Link-buttons: All <a class="btn"> converted to Button { href }
  • Toasts: 8 hand-rolled toast files converted to library Toast/ToastContainer
  • Dismissible alerts: All btn-close patterns converted to Alert { dismissible, on_dismiss }
  • CSS cleanup: ~665 lines of Bootstrap-overriding CSS removed across 13 service UIs, replaced with utility classes
  • Auth sidebar: Fixed with pure Bootstrap small class (no custom CSS)

Build & Deploy Notes

Prerequisites

All local repos must be on development_dioxus_bootstrap (or _2 for hero_os/archipelagos) branches. The build system mounts local source code into Docker — it uses whatever is on disk.

Build Command

cd hero_services
HERO_OS_FEATURES="web,bootstrap-islands" bash docker/build-local.sh

HERO_OS_FEATURES is needed because hero_os_app default features don't include bootstrap-islands. After the WIP branches merge to development, the default features should be updated and this env var becomes unnecessary.

Package & Push to Registry

cd .. && docker build -f hero_services/Dockerfile.pack -t forge.ourworld.tf/lhumina_code/hero_zero:devbootstrap .
docker push forge.ourworld.tf/lhumina_code/hero_zero:devbootstrap

Deploy to TFGrid

cd hero_services/deploy/single-vm
make destroy ENV=herodevbootstrap   # tear down old VM
make deploy ENV=herodevbootstrap    # fresh deploy on node 50

Post-Deploy Patches (issue #25)

Several services need manual zinit config patches after deploy:

  • Binary names may not match TOML configs
  • Some services need serve subcommand added
  • This is a known gap tracked in hero_services#25

Known Build Considerations

  • Repo renames: hero_cloudhero_compute, hero_forge_uihero_foundry_ui. Local directory names may still use old names — build-local.sh references old names (lines 195-196).
  • Archipelagos: build-wasm.sh clones from git if not found locally. Since build-local.sh mounts the local checkout, the clone should not trigger. If it does, set HERO_ARCHIPELAGOS_BRANCH=development_dioxus_bootstrap_2.
  • Docker base image: Uses forge.ourworld.tf/lhumina_code/hero_zero:base (pre-built with Rust toolchain, dx CLI, wasm32 target). Falls back to rust:1.93-bookworm if not available.

Next Steps & Dependencies

Current Status

  • #28 (this issue): Component conversion COMPLETE. Docker image built and pushed to forge.ourworld.tf/lhumina_code/hero_zero:devbootstrap. Parked on development_dioxus_bootstrap branches until merge prerequisites are met.
  • #23 (UI enhancements): DONE on development_mik_6_1. Running on herodev2.
  • #25 (service TOML configs): NOT YET DONE. Blocking deploy — fresh containers can't serve because service configs aren't generated properly.

Execution Order

  1. Fix #25 (service TOML configs / deploy fixes) — work on development_mik_6_1 branch across repos. This fixes the deploy configuration gap that prevents herodevbootstrap from serving after a clean container start.

  2. Merge development_mik_6_1development — brings both #23 (UI enhancements) and #25 (deploy fixes) into the base branch.

  3. Merge development INTO development_dioxus_bootstrap — preserves all #28 work while pulling in new changes from #23 and #25.

  4. Convert any new/changed UI from #23 to pure dioxus-bootstrap (same proven patterns).

  5. Test on herodevbootstrap — fresh deploy with working configs.

  6. Final merge development_dioxus_bootstrapdevelopment#28 is complete.

Dependency Chain

#25 (TOML configs) ──→ merge mik_6_1 → development ──→ merge development → dioxus_bootstrap ──→ convert new UI ──→ test ──→ final merge #28
## Summary Complete migration of Hero OS from Bootstrap/Askama server-rendered templates + JavaScript to **pure Dioxus WASM** using `dioxus-bootstrap-css`. Zero iframes, zero JavaScript, zero custom CSS overriding Bootstrap. Single WASM binary, offline-first, type-safe. **Status: Component conversion COMPLETE. Awaiting merge with `development_mik_6_1` before final merge to `development`.** Continues from [home#26](https://forge.ourworld.tf/lhumina_code/home/issues/26) (original migration plan). Live demo: https://herodevbootstrap.gent04.grid.tf --- ## What Was Achieved ### 100% Pure dioxus-bootstrap-css All **16 service UIs** and **44 archipelago islands** (60 UI crates total) now use dioxus-bootstrap-css components exclusively: - **572+ raw Bootstrap HTML patterns** converted to typed Rust components - **~665 lines of Bootstrap-overriding custom CSS** removed and replaced with Bootstrap utility classes on component props - **Zero raw `<div class="btn/card/alert/table/row/col/badge/spinner">` patterns** remaining - **Zero custom CSS that reimplements Bootstrap** — remaining CSS is genuinely app-specific (animations, split panes, syntax highlighting, log viewers) ### Components Used Throughout | Component | Replaces | |-----------|----------| | `Button { color, outline, size, href, target, download }` | `<button class="btn">` and `<a class="btn" href>` | | `Card { header_class, body_class, header, body, footer }` | `<div class="card">` with sub-divs | | `Alert { color, dismissible, on_dismiss }` | `<div class="alert">` | | `Table { size, bordered, hover, responsive }` | `<table class="table">` + `<div class="table-responsive">` | | `Row { }` / `Col { xs, sm, md, lg, xl }` | `<div class="row">` / `<div class="col-*">` | | `Container { fluid }` | `<div class="container">` | | `Badge { color, pill }` | `<span class="badge">` | | `Spinner { size, color }` | `<div class="spinner-border">` | | `Nav { tabs, pills, vertical }` + `NavItem` + `NavLink` | `<ul class="nav">` | | `Navbar { expand, brand }` | `<nav class="navbar">` | | `TabList { active, tabs }` | `<ul class="nav-tabs">` + `<div class="tab-content">` | | `Modal { }` | `<div class="modal">` | | `Toast { show, color, on_dismiss }` + `ToastContainer` | `<div class="toast">` | | `Breadcrumb` + `BreadcrumbItem` | `<nav class="breadcrumb">` | | `ListGroup` + `ListGroupItem` | `<ul class="list-group">` | | `InputGroup` | `<div class="input-group">` | | `Progress` / `ProgressBar` | `<div class="progress">` | | `Accordion` + `AccordionItem` | `<div class="accordion">` | ### dioxus-bootstrap-css Improvements (0.2.1 → 0.2.5) We own the library and improved it during this migration: | Version | Feature | |---------|---------| | 0.2.2 | `Button { href }` — renders `<a>` for link-buttons | | 0.2.3 | `Button { target, download }` — complete anchor attribute support | | 0.2.4 | `Alert { on_dismiss }` — callback for external state management | | 0.2.5 | Toast headerless close button (Bootstrap 5.3 d-flex pattern) + `on_dismiss` | ### Shell Fixes (hero_os) - `.desktop` bottom gap: 112px → 130px (prevents dock overlap with window content) - Consistent `py-3` top padding on all service UIs for proper spacing in hero_os windows - `overflow: auto` on island content wrapper divs (enables scrolling) --- ## Technical Approach ### The Gold Standard Pattern Every service UI follows this pattern (proven with the Embedder test example): ```rust Navbar { expand: NavbarExpand::Lg, class: "bg-body-tertiary border-bottom", brand: rsx! { ... } } Container { fluid: true, class: "py-4", Row { class: "g-3", Col { lg: ColumnSize::Span(3), Card { class: "mb-3", header_class: "d-flex justify-content-between align-items-center py-2", body_class: "py-2", header: rsx! { span { class: "small", ... } }, body: rsx! { Table { size: Size::Sm, borderless: true, class: "mb-0 small", ... } }, } } Col { lg: ColumnSize::Span(9), TabList { active: active_tab, tabs: vec![...] } } } } ``` Key principles: - **Bootstrap utility classes** (`small`, `py-2`, `btn-sm`, `form-control-sm`) instead of custom CSS font-size overrides - **Component props** (`header_class`, `body_class`, `responsive: true`) instead of wrapper divs - **No custom CSS** for anything Bootstrap provides — remaining CSS is only for app-specific patterns --- ## Branches and PRs All work is on `development_dioxus_bootstrap` branches. **DO NOT MERGE** — see merge plan below. ### hero_os + hero_archipelagos (branch: `development_dioxus_bootstrap_2`) | Repo | PR | |------|----| | hero_os | [#27](https://forge.ourworld.tf/lhumina_code/hero_os/pulls/27) | | hero_archipelagos | [#38](https://forge.ourworld.tf/lhumina_code/hero_archipelagos/pulls/38) | ### 15 Service UIs (branch: `development_dioxus_bootstrap`) | Repo | PR | |------|----| | hero_auth | [#7](https://forge.ourworld.tf/lhumina_code/hero_auth/pulls/7) | | hero_redis | [#14](https://forge.ourworld.tf/lhumina_code/hero_redis/pulls/14) | | hero_embedder | [#11](https://forge.ourworld.tf/lhumina_code/hero_embedder/pulls/11) | | hero_indexer_ui | [#3](https://forge.ourworld.tf/lhumina_code/hero_indexer_ui/pulls/3) | | hero_aibroker | [#26](https://forge.ourworld.tf/lhumina_code/hero_aibroker/pulls/26) | | hero_services (includes hero_shrimp) | [#54](https://forge.ourworld.tf/lhumina_code/hero_services/pulls/54) | | hero_compute (was hero_cloud) | [#18](https://forge.ourworld.tf/lhumina_code/hero_compute/pulls/18) | | hero_voice | [#7](https://forge.ourworld.tf/lhumina_code/hero_voice/pulls/7) | | hero_proxy | [#3](https://forge.ourworld.tf/lhumina_code/hero_proxy/pulls/3) | | hero_inspector | [#6](https://forge.ourworld.tf/lhumina_code/hero_inspector/pulls/6) | | hero_foundry | [#11](https://forge.ourworld.tf/lhumina_code/hero_foundry/pulls/11) | | hero_books | [#82](https://forge.ourworld.tf/lhumina_code/hero_books/pulls/82) | | hero_osis | [#13](https://forge.ourworld.tf/lhumina_code/hero_osis/pulls/13) | | hero_foundry_ui (was hero_forge_ui) | [#6](https://forge.ourworld.tf/lhumina_code/hero_foundry_ui/pulls/6) | | zinit | [#60](https://forge.ourworld.tf/geomind_code/zinit/pulls/60) | --- ## Merge Plan Our `development_dioxus_bootstrap` branches were forked from `development`. Meanwhile, `development_mik_6_1` has newer UI improvements (hero_compute nicer UI, foundry rename, etc.) not yet merged to `development`. This is what runs on herodev2. ### Steps 1. **Merge `development_mik_6_1` into `development`** across all repos — brings herodev2's latest UI to the base branch 2. **Merge `development` INTO `development_dioxus_bootstrap`** branches (not the other way) — preserves our work while pulling in new UI changes 3. **Resolve merge conflicts** — our converted files vs their updated files 4. **Convert any new/changed UI** from `development_mik_6_1` to pure dioxus-bootstrap (same proven patterns) 5. **Test on herodevbootstrap** — verify everything works 6. **Merge `development_dioxus_bootstrap` PRs into `development`** — the final merge ### Why merge (not rebase) - Preserves full history of both lines of work - Creates clear merge commits showing where they joined - No risk of losing commits from rewriting history ### Expected conflict areas - `app.rs` files (both branches modified) - Navbar components (renames in mik_6_1, conversions in bootstrap) - CSS files (we cleaned them, they may have added new rules) - `Cargo.toml` (dependency versions) --- ## What Remains After Merge After steps 1-4, any new UI code from `development_mik_6_1` needs the same dioxus-bootstrap conversion. This should be straightforward — we've established the exact patterns for every Bootstrap component type. The conversion is mechanical. --- ## Progress Log - **Phase 1-4**: 16 service UIs converted from raw HTML to dioxus-bootstrap-css components (572+ patterns) - **Phase 5**: 44 archipelago islands converted - **Shell fixes**: Desktop bottom gap, top padding, scroll overflow - **dioxus-bootstrap-css**: Published 0.2.2 → 0.2.5 (Button href/target/download, Alert on_dismiss, Toast headerless) - **Link-buttons**: All `<a class="btn">` converted to `Button { href }` - **Toasts**: 8 hand-rolled toast files converted to library Toast/ToastContainer - **Dismissible alerts**: All btn-close patterns converted to `Alert { dismissible, on_dismiss }` - **CSS cleanup**: ~665 lines of Bootstrap-overriding CSS removed across 13 service UIs, replaced with utility classes - **Auth sidebar**: Fixed with pure Bootstrap `small` class (no custom CSS) --- ## Build & Deploy Notes ### Prerequisites All local repos must be on `development_dioxus_bootstrap` (or `_2` for hero_os/archipelagos) branches. The build system mounts local source code into Docker — it uses whatever is on disk. ### Build Command ```bash cd hero_services HERO_OS_FEATURES="web,bootstrap-islands" bash docker/build-local.sh ``` `HERO_OS_FEATURES` is needed because `hero_os_app` default features don't include `bootstrap-islands`. After the WIP branches merge to `development`, the default features should be updated and this env var becomes unnecessary. ### Package & Push to Registry ```bash cd .. && docker build -f hero_services/Dockerfile.pack -t forge.ourworld.tf/lhumina_code/hero_zero:devbootstrap . docker push forge.ourworld.tf/lhumina_code/hero_zero:devbootstrap ``` ### Deploy to TFGrid ```bash cd hero_services/deploy/single-vm make destroy ENV=herodevbootstrap # tear down old VM make deploy ENV=herodevbootstrap # fresh deploy on node 50 ``` ### Post-Deploy Patches (issue #25) Several services need manual zinit config patches after deploy: - Binary names may not match TOML configs - Some services need `serve` subcommand added - This is a known gap tracked in hero_services#25 ### Known Build Considerations - **Repo renames**: `hero_cloud` → `hero_compute`, `hero_forge_ui` → `hero_foundry_ui`. Local directory names may still use old names — `build-local.sh` references old names (lines 195-196). - **Archipelagos**: `build-wasm.sh` clones from git if not found locally. Since `build-local.sh` mounts the local checkout, the clone should not trigger. If it does, set `HERO_ARCHIPELAGOS_BRANCH=development_dioxus_bootstrap_2`. - **Docker base image**: Uses `forge.ourworld.tf/lhumina_code/hero_zero:base` (pre-built with Rust toolchain, dx CLI, wasm32 target). Falls back to `rust:1.93-bookworm` if not available. --- ## Next Steps & Dependencies ### Current Status - **#28 (this issue)**: Component conversion COMPLETE. Docker image built and pushed to `forge.ourworld.tf/lhumina_code/hero_zero:devbootstrap`. Parked on `development_dioxus_bootstrap` branches until merge prerequisites are met. - **#23 (UI enhancements)**: DONE on `development_mik_6_1`. Running on herodev2. - **#25 (service TOML configs)**: NOT YET DONE. Blocking deploy — fresh containers can't serve because service configs aren't generated properly. ### Execution Order 1. **Fix #25** (service TOML configs / deploy fixes) — work on `development_mik_6_1` branch across repos. This fixes the deploy configuration gap that prevents `herodevbootstrap` from serving after a clean container start. 2. **Merge `development_mik_6_1` → `development`** — brings both #23 (UI enhancements) and #25 (deploy fixes) into the base branch. 3. **Merge `development` INTO `development_dioxus_bootstrap`** — preserves all #28 work while pulling in new changes from #23 and #25. 4. **Convert any new/changed UI** from #23 to pure dioxus-bootstrap (same proven patterns). 5. **Test on herodevbootstrap** — fresh deploy with working configs. 6. **Final merge `development_dioxus_bootstrap` → `development`** — #28 is complete. ### Dependency Chain ``` #25 (TOML configs) ──→ merge mik_6_1 → development ──→ merge development → dioxus_bootstrap ──→ convert new UI ──→ test ──→ final merge #28 ```
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/home#28
No description provided.