SBS Controls Behavior Documentation
Date: October 25, 2025
Context: BAER/Disturbed SBS upload and uniform generation controls
Overview
The SBS (Soil Burn Severity) controls coordinate the Disturbed, Baer, and Map controllers so users can upload a custom raster or generate a uniform severity map while keeping the Leaflet overlay and summary panel in sync.
Mode System
Two Modes (Persisted)
- Upload Mode (
sbs_mode = 0): Upload custom.tifor.imgraster - Uniform Mode (
sbs_mode = 1): Generate uniform low/moderate/high severity raster (uniform_severitystores the chosen level)
File Structure
Frontend
-
Controller:
wepppy/weppcloud/controllers_js/disturbed.js- Handles upload, uniform generation, removal
- Syncs with
baer.jscontroller for map display - Manages "Current SBS map" filename display
-
Template:
wepppy/weppcloud/templates/controls/disturbed_sbs_pure.htm- Two control sections:
#sbs_mode0_controls(upload),#sbs_mode1_controls(uniform) - Radio buttons to switch modes (persisted via
sbs_mode) - Summary panel (
#info) is filled by the BAER controller viaload_modify_class()
- Two control sections:
-
Summary Template:
wepppy/weppcloud/templates/mods/baer/classify.htm- Rendered by
view/modify_burn_class - Injected into the SBS summary panel after uploads or uniform builds
- Shows the active uniform severity when
sbs_modeis 1
- Rendered by
-
Map Controller:
wepppy/weppcloud/controllers_js/map.js- Provides
MapController.getInstance()which Disturbed/Baer use to add or remove the "Burn Severity Map" overlay - Keeps the Leaflet control (
map.ctrls) in sync to avoid duplicate or orphaned legend entries
- Provides
Backend
-
Routes:
wepppy/weppcloud/routes/nodb_api/disturbed_bp.pytask_upload_sbs: Upload and validate rastertask_build_uniform_sbs: Generate uniform severity rastertask_remove_sbs: Remove SBS raster- Upload/uniform responses include
{ Content: { disturbed_fn: ... } }(no HTML payload today) view/modify_burn_class: Returns HTML summary used in the SBS panel
-
NoDb:
wepppy/nodb/mods/baer/baer.pyandwepppy/nodb/mods/disturbed/disturbed.py- Stores:
baer_fn(filename),has_map(boolean),sbs_mode,uniform_severity
- Stores:
Tested Behaviors
✅ Upload Mode
- Initial state: No SBS, Upload mode selected by default
- File selection triggers auto-upload: No separate "Upload" button
- Success:
- Map appears on Leaflet with "Burn Severity Map" layer
- "Current SBS map" display shows filename
- Remove button: Removes map layer and legend; filename display currently remains populated
✅ Uniform Mode
- Switch to Uniform mode: Radio button hides upload controls, shows 4 buttons
- Four buttons (all same 240px width):
- Use Uniform Low SBS
- Use Uniform Moderate SBS
- Use Uniform High SBS
- Remove SBS
- Success:
- Map appears on Leaflet with "Burn Severity Map" layer
- BAER summary panel calls out the selected uniform severity
- Remove button: Same behavior as upload mode (map + legend cleared, filename display persists)
✅ Re-upload / Regenerate
- Multiple uploads: Old layer removed before new one added (no accumulation)
- Multiple uniform generations: Same behavior, replaces existing
- Switch modes: Can upload, then generate uniform, or vice versa - last one wins
✅ Reload Behavior
- After upload: Page reloads → Upload mode selected with filename restored
- After uniform: Page reloads → Uniform mode selected with BAER summary showing the stored severity
- Bootstrap:
disturbed.bootstrap()callsbaer.bootstrap()which callsbaer.show_sbs()to render map
Bootstrap & State Restoration
- Run bootstrap JSON injects
controllers.disturbed/controllers.baerwithmodeanduniformSeverity(run_page_bootstrap.js.j2). Disturbed.bootstrap(ctx)seeds the cachedhas_sbsflag, applies the controller context (radio buttons + cached severity), and replaysBaer.bootstrap(ctx)when an SBS exists.Baer.bootstrapbinds event listeners and issues an initialshow_sbs()/load_modify_class()so map overlays and summary content match the persisted state.
Summary Refresh Flow
- Upload/uniform build responses trigger
disturbed:uniform:completed/SBS_UPLOAD_TASK_COMPLETE. - Disturbed schedules
baer.show_sbs()+baer.load_modify_class()to redraw the map overlay and re-rendermods/baer/classify.htm. - The template highlights the active uniform severity (when
sbs_mode == 1), keeping the info panel aligned with backend state.
Event Flow
Upload Flow
1. User selects file → auto-upload triggered
2. disturbed.uploadSbs()
- Clear hints
- POST /tasks/upload-sbs with FormData (use `/rq-engine/api` via `url_for_run(..., { prefix: "/rq-engine/api" })`)
3. Backend validates, saves to baer_dir
4. Response: { result: { disturbed_fn: "..." } }
5. Frontend:
- Updates "Current SBS map" display
- Triggers SBS_UPLOAD_TASK_COMPLETE event
- Calls baer.show_sbs() to render map
- Calls baer.load_modify_class() to refresh the summary/classification panel
Uniform Flow
1. User clicks "Use Uniform [Low|Moderate|High] SBS"
2. disturbed.buildUniformSbs(severity)
- Clear hints
- POST /tasks/build_uniform_sbs with {value: severity}
3. Backend generates uniform raster
4. Response: { result: { disturbed_fn: "..." } }
5. Frontend: (same as upload flow with BAER summary reflecting uniform severity)
Remove Flow
1. User clicks "Remove SBS" (in either mode)
2. disturbed.removeSbs()
- POST /tasks/remove_sbs
3. Backend deletes raster file
4. Response: {}
5. Frontend:
- Removes map layer directly via MapController
- Removes layer from control
- Clears SBS legend
- Clears the SBS summary panel (`infoAdapter.html("")`)
- Leaves "Current SBS map" display populated (needs follow-up if we want clearing)
- Mode selection remains unchanged
- Updates has_sbs flag
Cross-Controller Communication
Disturbed ↔ Baer
- Two separate forms:
#sbs_upload_form(Disturbed) and#baer_form(Baer) - Event bridge: Disturbed emits
SBS_UPLOAD_TASK_COMPLETE/SBS_REMOVE_TASK_COMPLETE; Baer listens and re-renders the summary panel viaload_modify_class(). - Direct calls: Disturbed invokes
baer.show_sbs()/load_modify_class()to refresh the overlay and classification UI after uploads or uniform builds. - Timing guard: A 100 ms
setTimeoutensures the Baer form has mounted before dispatching map refresh calls.
Map Controller Integration
- Overlay lifecycle: Disturbed and Baer both call
MapController.getInstance(); when unavailable the code guards with try/catch so backend state still updates. - Legend hygiene:
baer.show_sbs()clears existing "Burn Severity Map" entries from both the map and control before adding the new overlay to prevent duplicates. - Removal path: Disturbed explicitly removes the overlay and legend during
remove_sbsso the UI immediately reflects the cleared state.
Cross-Controller Communication
Disturbed ↔ Baer
- Two separate forms:
#sbs_upload_form(disturbed) and#baer_form(baer) - Communication: Via events and direct method calls
disturbed.triggerEvent('SBS_UPLOAD_TASK_COMPLETE', data)- Direct calls:
baer.show_sbs(),baer.load_modify_class()
- Timing: 100ms setTimeout to ensure baer form is ready
Map Layer Management
- Layer name: "Burn Severity Map"
- Cleanup: Must remove both from map (
map.removeLayer) and control (map.ctrls.removeLayer) - Orphaned layers:
baer.showSbs()checks for existing layer and removes before adding new - Legend: Separate element
#sbs_legend, must be cleared on remove
CSS Styling
Button Widths
#sbs_mode1_controls .wc-button-row {
margin-bottom: var(--wc-space-md);
}
#sbs_mode1_controls .wc-button-row .pure-button {
min-width: 240px; /* Ensures all 4 buttons same width */
justify-content: center;
}
Table Formatting (Classification UI)
.wc-baer-classify__table--breaks {
max-width: 600px;
}
.wc-text-right {
text-align: right;
}
.wc-text-bold {
font-weight: bold;
}
Testing Checklist
Upload Mode
- File selection auto-triggers upload
- Success: Map appears with correct bounds
- Success: "Current SBS map" displays filename
- Summary panel renders BAER classification content
- Error: Error message shown in Status panel
- Re-upload: Old layer removed, new one appears
- Remove: Map and legend disappear; filename display stays populated
Uniform Mode
- All 4 buttons same width (240px)
- Low/Moderate/High generate different files
- Success: Map appears with correct bounds
- Multiple generations: No layer accumulation
- Summary panel updates to reflect uniform severity controls
- Remove: Map disappears, legend clears, mode/filename remain
Reload Scenarios
- After upload: Map reappears via bootstrap
- After uniform: Map reappears via bootstrap
- Mode selector reflects persisted
sbs_mode - Summary content matches persisted state
Cross-Browser
- Safari (macOS)
- Chrome
- Firefox
Related Files
Frontend
wepppy/weppcloud/controllers_js/disturbed.jswepppy/weppcloud/controllers_js/baer.jswepppy/weppcloud/templates/controls/disturbed_sbs_pure.htmwepppy/weppcloud/templates/mods/baer/classify.htmwepppy/weppcloud/static/css/ui-foundation.css
Backend
wepppy/weppcloud/routes/nodb_api/disturbed_bp.pywepppy/nodb/mods/baer/baer.pywepppy/nodb/mods/disturbed/disturbed.pywepppy/nodb/mods/baer/baer.pyi
Documentation
wepppy/weppcloud/controllers_js/README.mdwepppy/AGENTS.mddocs/dev-notes/sbs_controls_behavior.md(this file)
Changelog
October 25, 2025
- ✅ Fixed duplicate "Burn Severity Map" entries on reload
- ✅ Fixed form value capture bug (read before startTask clears)
- ✅ Removed Upload SBS button, added auto-upload on file select
- ✅ Fixed layer accumulation on re-upload
- ✅ Fixed filename display update after upload
- ✅ Fixed remove functionality (map + legend)
- ✅ Made uniform buttons consistent width (240px)
- ✅ Persists both the
sbs_modeanduniform_severityfor reload - ✅ classify.htm is
sbs_modeaware