Skip to content

Infrastructure device client — API-backed add/edit/persist (fan integration 2/5) #742

Description

@rongxin-liu

Summary

Wire the ProtoFleet infrastructure-devices UI (/fleet/infrastructure) to the InfrastructureService that landed in #724, replacing the local-React-state device list with persisted CRUD. Second PR of the facility-fan curtailment series; full design in docs/plans/2026-07-09-facility-fan-curtailment-integration-plan.md (Phase 2, including the post-PR 1 implementation prep notes).

No device behavior activates from this work — the write path lands with the later Modbus I/O and reconciler-sequencing phases. This is inventory/CRUD surface only.

Scope

  • infrastructureClient registration in client/src/protoFleet/api/clients.ts + new useInfrastructureDevices hook (list/create/update/delete), mirroring useCurtailmentResponseProfiles
  • FleetInfraPage / InfraDeviceList fetch devices from the API; state ownership moves from InfraDeviceList.localDevices into the hook, with devices + mutation callbacks passed down
  • ManualAddStep rework for the adapter model: driver-type select (Modbus TCP, sole option) rendering a per-driver-type form module (e.g. driverForms/modbusTcp.tsx) that owns driver_config encode/decode; register-address field takes the raw application address with field-help copy warning against the 4xxxx convention and noting the wire-level off-by-one
  • Each form module also exports a connection-summary renderer for a single generic "Connection" list column and the detail modal's info rows (endpoint/port/unit-ID move into opaque driver_config)
  • Detail-modal edit rework onto the same form module, submitting through the update/delete RPCs — the detail modal stays the canonical edit surface
  • API-backed list states: list-level loading and fetch-error with retry; add/edit modals surface RPC failures inline (actionError banner pattern); the Enabled switch reverts on failure with an error toast, sending only the optional bool enabled (server preserves omitted fields)
  • Graceful degradation where driver_config is redacted (empty string) for site:read-only callers — connection summary renders an em dash or hides rather than failing to parse
  • Hide the Status and Last-seen columns, their filters, the offline Alert styling, and the detail modal's status header until v2 read-back can populate them
  • Tests: extend InfraDeviceList.test.tsx, ManualAddStep.test.tsx, InfraDeviceDetailModal.test.tsx, FleetInfraPage.test.tsx; add an API-hook test (mirror useCurtailmentResponseProfiles.test.tsx)

Out of scope (later phases of the fan integration)

  • Response-profile fan settings (facility_fan_device_ids, delays) + the device deletion reference-guard that depends on that column (PR 3)
  • Modbus TCP write path + dev simulator (PR 4)
  • Reconciler fan sequencing (PR 5)

Repo hygiene

No proto/schema changes expected; routing is already wired (/fleet/infrastructure is routed and prefetched). Feature branch (never main); just lint before PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions