intrepidshape/elm-web3-ui/2.4.0

NOTE: the latest version is 4.0.0

Web3.Ui.RemoteCall

The remote-data type for correlation-id port round-trips -- the missing foundation under every read in a dapp.

Every elm-web3 read (balance, contract call, fee, block...) is fire-and-forget through a port, matched back by a correlation id. Modelling each one by hand means every dapp reinvents Maybe (Result String a) plus an in-flight flag plus id bookkeeping. RemoteCall is that shape, once, with the id bookkeeping built in:

type alias Model =
    { reserves : RemoteCall Reserves }


-- fire
( { model | reserves = RemoteCall.request "reserves-1" model.reserves }
, web3Cmd (Call.encode reservesCall)
)


-- resolve (ONLY applies if the id matches the one in flight --
-- a stale response for an earlier request cannot clobber a newer one)
{ model | reserves = RemoteCall.resolve incomingId result model.reserves }


-- render
RemoteCall.view
    { skeleton = Skeleton.line []
    , failed = \\err -> Html.text err
    }
    viewReserves
    model.reserves

The id guard follows the same rule the Web3.Sign machine proves in elm-web3's SignSpec.tla: a response for a different correlation id never completes the pending call.

type RemoteCall a
= NotAsked
| Loading String
| Ready a
| Failed String

The four honest states of a port round-trip. Loading carries the correlation id of the request in flight.

The initial state.

request : String -> RemoteCall a -> RemoteCall a

Mark a request in flight under the given correlation id. Always transitions -- firing a new request supersedes whatever came before, and its id becomes the only one resolve will accept.

resolve : String -> Result String a -> RemoteCall a -> RemoteCall a

Apply a response -- but only if its correlation id matches the request in flight. A stale or misrouted response (an earlier request answered late, another component's id) is dropped on the floor, never shown as fresh data.

Back to NotAsked (e.g. on wallet disconnect or chain switch, when the data no longer describes anything).

map : (a -> b) -> RemoteCall a -> RemoteCall b

Transform the value inside Ready.

withDefault : a -> RemoteCall a -> a

The value, or a fallback.

toMaybe : RemoteCall a -> Maybe a

Just the value when Ready.

isLoading : RemoteCall a -> Bool

True while a request is in flight.

correlationId : RemoteCall a -> Maybe String

The correlation id in flight, if any.

view : Slots msg -> (a -> Html msg) -> RemoteCall a -> Html msg

Render a RemoteCall, wrapped in a <div class="web3-remote"> whose modifier tracks the state -- --loading carries aria-busy="true" so assistive tech knows the region is settling.

CSS classes: web3-remote, web3-remote--loading, web3-remote--ready, web3-remote--failed.

type alias Slots msg =
{ skeleton : Html msg
, failed : String -> Html msg
}

What to render for the non-Ready states. NotAsked renders the skeleton too -- from the user's point of view "not fetched yet" and "fetching" look the same.