agentleFS
jangabrielssonjangabrielsson/flua/.github/skills/quickapp-ui/SKILL.md

quickapp-ui

Skill1 starsChanged 15 days agoMITView on GitHub

HC3 QuickApp UI at runtime: self:updateView(...) for every element type (label, button, slider, switch, select, multi) — which properties and values each accepts (text, value, visible, disabled, image, min/max/step, color, options, selectedItem/selectedItems/values), the value rules (strings, select matching by option value, not text), the UI event contract (onReleased/onLongPress*/onToggleOn/onToggleOff/onChanged/onToggled and their event.values shapes), and how to assert or drive UI state in tests (self:getView(), _FLUA.uiEvent, /plugins/callUIEvent). USE FOR: changing UI elements at runtime, updating a label/slider/select from QA code, debugging why an updateView call does not show in the viewer, wiring UI callbacks.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    disabled: only disables buttons and sliders in the viewer.

    line 66

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

QuickApp UI at Runtime: updateView, Events, Viewer Semantics

How UI elements change while the QA runs. For the --%%u: directive syntax that declares the elements, see /quickapp-types; this skill covers what happens after that — self:updateView, the callback events, and how the flua viewer renders each element. flua matches the HC3 5.221 behavior; where they differ, it is called out below.

The one method: self:updateView

self:updateView(componentName, property, value)

It writes value under property for the named component (HTTP /plugins/updateView). The viewer merges this live state over the declared element on every poll, and self:getView() returns the merged view — assert UI state with it.

updateView reference per element

  • label — text (string, HTML allowed: <font color='red'>, <table>, …)
  • button — text (string), image (named icon from the viewer's icon set; unknown names render text-only), disabled (bool)
  • slider — value (string), min/max/step (strings), unit (string, rendered right of the value: "21 °C"), color (CSS color, sets the thumb), disabled (bool)
  • switch — value ("true"/"false" strings), text, image
  • select (single) — selectedItem (scalar), options (full replacement of the option list), values (list; the 5.221 schema reads the first entry), text (the placeholder shown when nothing matches)
  • multi — selectedItems (list of values), options, values, text
  • every element — visible (bool; false hides the element — it takes no row space)
self:updateView("statusLbl", "text", "Zone 1: 21.5°C")
self:updateView("setpoint", "value", "21.5")
self:updateView("autoSwitch", "value", "true")
self:updateView("modeSelect", "selectedItem", "eco")
self:updateView("modeSelect", "options", {{type='option',text='Eco',value='eco'},
                                              {type='option',text='Manual',value='manual'}})
self:updateView("tagMulti", "selectedItems", {"1", "3"})
self:updateView("warnLbl", "visible", false)

Value rules that bite

  • Values are strings. Sliders and switches compare by string; always tostring(n) numbers. updateView("s", "value", 75) renders but compares as "75" on the wire — pass strings deliberately.
  • selectedItem matches an option's value, not its text. Setting the label (e.g. "Partly cloudy" when the option values are clear, rain, …) selects nothing and the dropdown shows its placeholder. Normalize the value to the option-value vocabulary before the call.
  • options replaces the whole list — send the complete new list, not a delta. It is a structure change (the dropdown rebuilds).
  • selectedItems is a Lua table, selectedItem a scalar. On the HC3, using "values" where the canonical property applies silently does nothing; prefer selectedItem/selectedItems.
  • disabled only disables buttons and sliders in the viewer; switches and selects ignore it (HC3 UI parity — use visible to hide instead).
  • Viewer precedence: live updateView state wins over the user's last click on the element, which wins over the declared directive value. The QA is not expected to echo the user's interaction back — but once the QA sets a live value, it wins until changed again.

The UI event contract

The viewer delivers interactions through event = {deviceId, eventType, elementName, values}. Wire callbacks with the directive's event keys (--%%u:{slider='s',text='S',onChanged='handler'}); the QA method receives the event table.

  • button — onReleased, onLongPressDown, onLongPressReleased. event.values is empty (no value).
  • switch — onReleased, plus the 5.221 split events onToggleOn / onToggleOff (sent when declared; the viewer prefers them). The value is a string: event.values[1] == "true" / "false" — not a boolean.
  • slider — onChanged. event.values[1] is the value as a string; tonumber() it.
  • select — onToggled. event.values[1] is the picked option value (string).
  • multi — onToggled. event.values[1] is the list of picked values (flua restores the list; on the real HC3 they arrive comma-joined in the single value parameter).
function QuickApp:modeToggled(event)
  self:updateView("modeSelect", "selectedItem", event.values[1])  -- echo the pick
end

Asserting and driving UI state in tests

  • self:getView() — the QA's current rendered view including all updateView changes; parse it to assert label texts, slider values, selectedItem, …
  • _FLUA.uiEvent(elementName, eventType[, value]) — inject a UI event from a test/verify QA, exactly like a tap on the real UI would deliver it.
  • GET /plugins/callUIEvent?deviceID=<id>&elementName=<n>&eventType=<t>[&value=<v>] — the viewer's channel; drive it from outside the QA (curl, tests). POST with a JSON body is the proxy channel.
_FLUA.uiEvent("setpoint", "onChanged", "21.5")
local view = self:getView()
assert(tostring(view.body.sections.items[1].components[1].value) == "21.5")

A runnable QA exercising every element's updateView and callbacks lives in templates/updateview-demo.lua — run it with flua --ui and watch the viewer, or drive it from a test QA.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.