#What device admin UIs must do well
AddedA device admin UI is the control panel for a machine the operator usually can't see. A video bar on a meeting-room wall, a camera, a phone, a gateway in a rack: each runs a small web server, and an IT admin, an AV technician or a support engineer opens the device's address in a browser to see whether it's healthy, change its settings, read its logs and update its software. The same jobs are often also done from a cloud management service for a whole fleet, but the on-device UI is the one that works when everything else is broken: no cloud account, no internet, just a laptop on the same network.
The device, paths (/api/v1/…) and firmware numbers in this chapter's models are made up to teach the patterns; Poly's own REST API, for comparison, uses /rest/… paths with no version segment (see Versioning strategies).
The mental model that explains most of the design rules is a pilot's cockpit for a remote aircraft. The admin is often not in the room; people may be in a meeting in that room right now; a wrong change can take the room offline, and the admin may then have no way back in. So the UI's first duty is to tell the truth about the device's state (including "I don't know, I can't reach it"), its second is to make changes safe (validate, preview, apply in one step, never lock the admin out), and its third is to keep working while the device is only half alive: rebooting, updating, or with a peripheral missing.
Poly's public documentation shows the shape on a real product. The Poly Video Mode Administrator Guide 4.7.0 (HP; its document-information page says "Last update: July 2025", although its copyright line reads 2021–2026) says that through the system web interface you can "configure every setting", while the local interface in the room "is intended only for the initial setup"; the same web interface also controls some calling functions, manages contacts, and is where software updates are configured and run. The 4.4.0 guide (November 2024) recommends restarting through the web interface, Poly Lens, the REST API, Telnet or SSH rather than pulling the power, and both say not to restart or power off during a software update. When a provisioning service manages the device, the 4.7.0 guide says provisioned settings become read-only in the web interface. Every one of those behaviours appears in this chapter as a general pattern; the guides don't describe how Poly built them, so nothing here claims to.
Most device admin UIs have the same five areas. Each answers a question the operator walks in with:
| Area | The operator's question | What it must show or do |
|---|---|---|
| Dashboard / status | "Is this room OK? If not, what do I do?" | Health summary, what needs attention with a link to fix it, firmware version, uptime, pending restart |
| Settings | "Change X without breaking anything." | Grouped, validated forms; which changes need a restart; who manages a setting (local or provisioned) |
| Diagnostics | "Why is the camera black?" | Connected peripherals, network tests, logs to download, call statistics, a restart button |
| Maintenance | "Update it, back it up, reset it." | Software update with real progress, config export and import, factory reset with clear consequences |
| Security | "Who can get in, and how?" | Accounts and roles, certificates and their expiry, which services (Telnet, SSH, REST) are enabled |
The dashboard is the page an admin sees first, so it carries the first rule: turn the raw status into "is this room OK, and if not, what do I do?" This model takes a status document like the one a device's GET /api/v1/status might return and reduces it to a sorted list of problems, each with an action and a link to the page that fixes it:
// The dashboard's first job: turn a raw status document into "is this room OK, and if not, what do I do?"
const now = Date.parse("2026-10-27T15:00:00Z"); // fixed clock so the output never changes
const status = {
system: { name: "Board Room", firmware: "4.2.1", uptimeSeconds: 3 * 86400, pendingRestart: ["provider"] },
network: { link: "up", ip: "10.0.4.20", dnsOk: true },
registration: { provider: "teams", state: "registered" },
peripherals: [
{ kind: "camera", name: "Main camera", connected: true },
{ kind: "microphone", name: "Ceiling mic 2", connected: false, lastSeen: "2026-10-27T14:12:00Z" },
{ kind: "display", name: "Left display", connected: true, resolution: "1080p" },
],
certificates: [{ name: "Web UI certificate", notAfter: "2026-11-08T00:00:00Z" }],
update: { available: "5.0.1", channel: "stable" },
};
const days = (iso) => Math.round((Date.parse(iso) - now) / 86400000);
const minutesAgo = (iso) => Math.round((now - Date.parse(iso)) / 60000);
const rules = [
(s) => s.network.link !== "up" && { level: "critical", text: "No network link", action: "Check the cable or Wi-Fi", page: "/network" },
(s) => s.registration.state !== "registered" && { level: "critical", text: `Not signed in to ${s.registration.provider}`, action: "Re-enter the room account", page: "/provider" },
(s) => s.peripherals.filter((p) => !p.connected).map((p) => ({ level: "critical", text: `${p.name} disconnected for ${minutesAgo(p.lastSeen)} min`, action: "Check its cable and power", page: "/devices" })),
(s) => s.system.pendingRestart.length && { level: "warning", text: `Restart needed to apply: ${s.system.pendingRestart.join(", ")}`, action: "Restart when the room is free", page: "/maintenance" },
(s) => s.certificates.filter((c) => days(c.notAfter) < 30).map((c) => ({ level: days(c.notAfter) < 0 ? "critical" : "warning", text: `${c.name} expires in ${days(c.notAfter)} days`, action: "Install a renewed certificate", page: "/security/certificates" })),
(s) => s.update.available && { level: "info", text: `Software ${s.update.available} available (running ${s.system.firmware})`, action: "Review release notes, schedule the update", page: "/maintenance/update" },
];
const order = { critical: 0, warning: 1, info: 2 };
const issues = rules.flatMap((rule) => rule(status) || []).sort((a, b) => order[a.level] - order[b.level]);
const overall = issues[0]?.level ?? "ok";
console.log(`${status.system.name}: ${overall.toUpperCase()} (${issues.length} items)`);
for (const i of issues) console.log(` ${i.level.padEnd(8)} ${i.text.padEnd(52)} → ${i.action} [${i.page}]`);Board Room: CRITICAL (4 items)
critical Ceiling mic 2 disconnected for 48 min → Check its cable and power [/devices]
warning Restart needed to apply: provider → Restart when the room is free [/maintenance]
warning Web UI certificate expires in 11 days → Install a renewed certificate [/security/certificates]
info Software 5.0.1 available (running 4.2.1) → Review release notes, schedule the update [/maintenance/update]- The status document is what the device knows: firmware, uptime, a
pendingRestartlist, network, registration with the conferencing provider, peripherals, certificates and an available update. Shown raw (a JSON viewer, or ten panels of equal weight), the admin has to work out what matters. The clock is fixed at15:00Zso the "minutes ago" and "days left" values are reproducible. - Each rule looks at one part of the status and returns nothing, one issue or a list of issues. Rules that find nothing return
false(network up, registered), andrule(status) || []drops them, so adding a check is adding one line, not editing a page. - The ceiling microphone has been gone since
14:12, so it becomes a critical issue "disconnected for 48 min" with "Check its cable and power" and a link to/devices. A missing mic is critical because the room still looks fine and meetings quietly fail; the dashboard is the only place anyone will notice. pendingRestart: ["provider"]becomes a warning: a saved change isn't running yet (the apply and restart topic builds this). The web certificate'snotAfteris 11 days away, under the 30-day threshold, so it's a warning now and would turn critical once expired.- The available update is only info: "available" isn't a problem, and showing it in red trains admins to ignore red. Sorting by level puts the mic first; the overall state is the worst level,
CRITICAL, with "4 items". - What this demonstrates: the dashboard is a function of device state, not a page of widgets. Because it's computed, the same function can run in a fleet view over a thousand devices, and you can unit-test "a disconnected mic is critical" without a browser.
The qualities interviewers and operators care about, each of which gets its own topic below:
- Truthful state. Every value shown says how fresh it is. If the device stopped answering, the page says so and shows the last-known values as stale, rather than freezing silently (unreachable states).
- Safe change. Settings are validated before they're sent and again on the device, applied as one batch, and changes that need a restart or could cut the admin off are flagged and protected (validation, apply flows).
- Recoverable maintenance. Updates verify the package before installing, keep the old version to roll back to, and report the real outcome after the reboot (update flows).
- Repeatable configuration. One device's setup can be exported, reviewed and applied to fifty others, and a provisioning server can own settings centrally (import and provisioning).
- Usable by everyone. Keyboard and screen-reader friendly, readable at the phone width an installer on a ladder uses, and translated (accessibility and localisation).
- The UI is the API's first client. Everything the UI does goes through the same public REST API that scripts, SDKs and management services use (see Modelling a device as resources). A setting that only the UI can change is a setting no customer can automate.
At 9:58 an admin changes the conferencing provider on a room device. Changing the provider needs a restart, and the device's status says it's in a call that's scheduled until 10:30. What should the UI do when the admin presses Save?
Show answer
Save the setting, don't restart, and say so: "Saved. The new provider starts after a restart. This room is in a call; restart now (ends the call) or later?"
- The device knows two facts the admin may not: the change needs a restart (a schema flag, see the next topic), and the room is busy (its status). The UI has both, so it shouldn't make the admin discover them by surprise.
- Silently restarting would drop a live meeting; that's the worst outcome, because people in the room had no say. Silently not restarting is the second worst: the admin walks away believing Teams is active.
- So the save goes through (the setting is stored), the device reports
pendingRestart: ["provider"], and the UI offers a choice: restart now, with a clear warning that the call ends, or later. "Later" can be a scheduled restart in a maintenance window: Poly's 4.7.0 guide documents a scheduled auto restart (daily or weekly) that would pick it up. - Until then the dashboard keeps a "Restart needed to apply: provider" warning, as in the model above, so whoever looks next sees the gap between saved and active.