Wiring Real State into a SCADA UI: When Buttons Actually Control Things

Building a SCADA coating system means dealing with 28 industrial baths that need to heat, cover, stir, and fill themselves—and the operator needs to see every change now. I faced a classic React problem: my EquipmentView and LineView components were wired to console.log. Time to make them actually control something.
The challenge was moving baths from a static import into useState so that every button press—whether it’s toggling a single heater or commanding all 28 units to close their covers at once—updates the shared state instantly across every tab and sidebar. The operator shouldn’t wait. They shouldn’t wonder if their click registered.
I started with OperatorWorkspace.tsx as the state owner. All bath data lives there, wrapped in useState. Then I threaded callback props down through EquipmentView and GroupControlBar. The heater buttons are straightforward: flip the boolean, re-render. But bulk operations like “ALL COVERS OPEN” demanded more thought.
Here’s where I chose asynchronous feedback over instant completion. When the operator hits “ВСЕ ОТКР” (all covers open), each bath’s cover toggles with a ~400ms delay between units. Why? Because in the real world, 28 hydraulic motors don’t move simultaneously. The UI reflects that reality—covers progress down the table one by one. If something jams, the operator sees where the sequence stops. It’s non-blocking too: a new command cancels any pending operations via clearTimeout, so the operator keeps control.
The “ДОЛИВ” (top-up) operation was trickier. Baths below 70% capacity need to refill, but they can’t all pump water at once. I broke it into five steps of incremental fill, staggered across units. Again, asynchronous—the UI stays responsive, and the operator watches the levels climb.
I wired everything through a simple callback pattern: EquipmentView receives onToggleHeater(bathId) and onToggleCover(bathId). GroupControlBar gets onBulkHeater(on), onBulkCovers(open), and onTopUp(). The Sidebar on LineView calls the same callbacks for single-bath controls. All roads lead back to state in OperatorWorkspace.
The result: No more console.log. Every button works. State syncs across tabs. Bulk commands feel real because they stagger, just like actual hardware would behave.
Now, when the JavaScript developer on my team asked why I didn’t just toggle everything instantly—“wouldn’t that be faster?”—I reminded them: faster isn’t always better in industrial UIs. Predictability and visibility beat speed. 😄
Metadata
- Session ID:
- grouped_scada-coating_20260222_0742
- Branch:
- feature/variant-a-migration
- Dev Joke
- Что общего у Emacs и кота? Оба делают только то, что хотят, и игнорируют инструкции