How-to guides
User interface (UI)
A Komod's browser UI is one or more Blazor components that KOFA's client loads at run time from the package. The UI only displays and sends commands; it has no ports of its own, the data comes from the server Komod.
Project
The UI is a separate project (X.Ui, Microsoft.NET.Sdk.Razor) that shares Package.props with the server project. The KomodClientAssemblies property of Package.props lists the dlls to load. The kofa-komod and kofa-komod-quickstart templates set this up.
View kinds
The [KomodView("<komod id>", ViewKind.X)] attribute binds the component to the Komod, and it derives from KomodComponentBase:
ViewKind |
Where it appears |
|---|---|
Widget |
A dashboard tile. |
Page |
The instance's full page. |
Settings |
A custom settings editor (otherwise a form is generated). |
A Komod can have one of each.
<div style="display:flex;flex-direction:column;gap:6px;font-variant-numeric:tabular-nums">
<div style="font-size:1.8rem;font-weight:600">
@(_temperature is { } t ? t.ToString("0.0", CultureInfo.InvariantCulture) + " °C" : "–")
</div>
<div style="display:flex;align-items:center;gap:8px">
<button type="button" @onclick="() => AdjustTargetAsync(-0.5)">−</button>
<span>cél: @(_target?.ToString("0.0", CultureInfo.InvariantCulture) ?? "–") °C</span>
<button type="button" @onclick="() => AdjustTargetAsync(+0.5)">+</button>
</div>
<div style="font-size:.85rem;opacity:.8">Fűtés: @(_heating ? "BE" : "KI")</div>
@if (_error is not null)
{
<div style="font-size:.8rem;color:#c42b1c">@_error</div>
}
</div>
Members given by the base class (KomodComponentBase)
| Member | Meaning |
|---|---|
InstanceId, InstanceLabel, KomodId |
The ids of the instance. |
Kofa (IKomodClientContext) |
Access to the server: subscribe, settings, command, file. |
Port("id") |
A PortRef to one of the instance's ports. |
AssetUrl("x.js") |
The URL of a file in the package's wwwroot/. |
InjectAsync, InvokeCommandAsync |
Shortcuts for submitting an input and for a command. |
Settings, SettingsChanged |
Only in a ViewKind.Settings view: the setting being edited and the change notification. |
Live data
SubscribeAsync<T> gives an asynchronous stream. You can subscribe to both output and input ports; the server thins the stream (maxRateHz) and re-subscribes by itself after a package reload.
protected override async Task OnInitializedAsync()
{
_target = ReadTarget(await Kofa.GetSettingsAsync(InstanceId, _cts.Token));
// Both an input and an output port can be subscribed; the server thins the stream to maxRateHz.
_loops.Add(Task.Run(async () =>
{
await foreach (var message in Kofa.SubscribeAsync<Scalar>(Port("temperature"), maxRateHz: 5, _cts.Token))
{
_temperature = message.Value.Value;
await InvokeAsync(StateHasChanged);
}
}));
_loops.Add(Task.Run(async () =>
{
await foreach (var message in Kofa.SubscribeAsync<BoolValue>(Port("heater"), maxRateHz: 5, _cts.Token))
{
_heating = message.Value.Value;
await InvokeAsync(StateHasChanged);
}
}));
}
Note
Stop the subscribing loop in DisposeAsync with the CancellationToken (see the whole template file), otherwise it keeps running after the page is left.
Settings editor
If the automatic form is not enough, write a [KomodView("<id>", ViewKind.Settings)] component. You get the setting being edited in the Settings parameter (filled with defaults), and report a change with the SettingsChanged callback. The change goes into the draft and takes effect after the Apply button.
For changes at run time (from a Widget or Page view) use IKomodClientContext.GetSettingsAsync / SaveSettingsAsync: the server validates, applies live (or restarts if OnSettingsChangedAsync returns false). On an error a KomodClientException comes with a message.
Static files and JavaScript
The UI project's wwwroot/ folder goes into the package, and the server serves it under /komods/<id>/<version>/wwwroot/. In the view AssetUrl gives the URL; a JS module is loaded like this:
_module = await JS.InvokeAsync<IJSObjectReference>("import", AssetUrl("remote-input.js"));
Keyboard, gamepad, pointer capture and similar event handling should stay in the Komod's own JS module.
Warning
The files in wwwroot/ can be downloaded without signing in, so do not put secrets into them. A view should call the server API not with a relative URL but with the methods of IKomodClientContext.
Size on the dashboard
The tile height can be adjusted. If the view can fill the space (map, image, 3D), the root element's height should follow the --kofa-view-height CSS variable, with a default of your own:
<div style="position:relative;height:var(--kofa-view-height, 260px)">…</div>
Styling
A Komod UI currently does not bring its own CSS to the client: give the style inline in the component (the template does so), or load a <link> from wwwroot/. The base font and colors come from the client; avoid fixed colors, for the light and dark theme.
Limits
- The released client is trimmed, not every framework API is available.
kofa-packwarns. - The UI cannot reach the server's file system directly; for files see Files.