# Dashboards and panels A **dashboard** is a grid of widgets bound to message names. It can show values and send controls across several flows. A **panel** assigns published dashboards to a paired screen, such as a wall tablet. ## Building one 1. Open **Dashboards → New dashboard**. 2. Enter edit mode, choose **Add widget** and select a type. 3. Bind the widget to a message in its settings. On desktop, drag and resize tiles on the grid. 4. **Publish** when the dashboard is ready. Edits stay in a draft; paired screens show the published version. On phones, tiles stack in one column and dragging is disabled, but settings remain editable. Controls can publish real values while you edit, so choose their targets with care. Your new Switch may already be flipping something! ## The widgets ### Display | Widget | Binds to | Shows | |---|---|---| | **Value** | anything | formatted reading, unit and precision | | **Gauge** | `float`, `int` | reading within a min/max range | | **Chart** | numeric messages, a query response or run metrics | up to five lines | | **Bar** | `float`, `int` | up to eight readings with separate scales | | **Icon** | numbers, booleans or strings | a glyph selected from the value | | **Text** | — | Markdown | | **Agenda** | `list` | upcoming items | | **Forecast** | `list` | an outlook strip | | **Notification** | `record` | title, body and severity | | **Media** | `image`, `audio`, `video`, `artifact` | image, audio or video | | **Player** | `record` | playback status and transport controls | | **Clock** | — | current time | | **Website** | — | embedded page or image | Every widget has a title. **Show title** controls its visibility; the title still names the widget for accessibility and published values. ### Input | Widget | Publishes | Settings | |---|---|---| | **Button** | fixed value | one-shot action | | **Buttons** | a value per button | grid of actions | | **Switch** | `bool` | on/off | | **Slider** | `float`, `int` | min, max, step; horizontal or vertical | | **Input** | text or number | free entry | | **Selector** | selected value | menu or row of choices | | **Colour** | list or string | HSV, RGB or hex | Colour defaults to `[h, s, v]`: hue 0–360°, saturation and brightness 0–100%. **Sends** can select RGB (`[r, g, b]`, 0–255) or hex (`"#rrggbb"`). HSV and RGB bind to `list`; hex binds to `str`. Controls publish to their bound messages. The flow canvas shows them as endpoints feeding the nodes that consume those messages. Bindings are checked in the editor and on the server. See [Payload types](../reference/payload-types.md). ## Charts Choose the chart's data source: - **Live:** recent numeric message history, updated as values arrive. - **Query:** publishes a `record` request containing `range_s` and `interval_s`, then draws a flow's `series` response. Include those fields in the answer so the chart can reject responses for a different window. - **Runs:** compares a numeric metric from named runs, a sweep or the latest runs of a flow. See [Runs](../concepts/runs.md). Multi-line charts show a legend as well as different colours. !!! tip "Skip the unfinished bucket" If your query aggregates into time buckets, leave out the bucket still filling. Otherwise an incomplete total can look like a sudden drop. ## Media tiles Media messages contain artifact references; the widget loads the bytes they name. **Crop or fit** controls image sizing. **Play as it arrives** enables autoplay, subject to the browser's rules for sound. For local streams, `volatile=True` artifacts can be pushed over the websocket with their message. Stored artifacts are fetched individually, as are frames viewed through a portal. Use occasional snapshots for remote screens. For continuous video, set **Live stream** to a browser-compatible camera URL. The browser must be able to reach that URL; enrollment does not expose the camera itself. See [Media payloads](../reference/payload-types.md#image-audio-video). ## Player tiles A Player reads a status `record` and publishes commands to a separate `str` message. | Status field | Meaning | |---|---| | `title`, `artist`, `album` | track details | | `status` | `play`, `pause`, `stop`, `load` or `off` | | `position`, `duration` | seconds | Controls send `toggle`, `next`, `prev` and `seek:`. Your receiving node translates those into device actions. The position advances in the browser between readings and resets to each fresh reading. ## Website tiles Set **Address** to a page to embed, or choose **Image** for a snapshot or MJPEG URL. A website may refuse embedding. Embedded pages run in a sandbox without cookies or storage by default. **Trusted site** permits the site's own origin, cookies and storage. Use it only for a trusted destination. The app blocks trusted embeds of its own origin, including the portal origin, to protect your session. ## Dashboard settings Open **Dashboard settings** from the dock. Each setting can hold a fixed value or follow a message chosen in **Driven by**. The fixed value is the fallback when no usable message value is available. | Setting | Choices | Message type | |---|---|---| | **Look** | `fluksio`, `material`, `glass` | `str` | | **Theme** | `system`, `light`, `dark` | `str` | | **Palette** | ordered hex colours | `list` | | **Background** | image URL | `str` | | **Lock** | read-only on/off | `bool` | To change one on a schedule, have a scheduled node publish its bound message. ### Look and theme **Fluksio** is the default look. **Material** uses flat tonal cards; **Glass** uses translucent tiles. Widgets work the same in all three. Theme follows the chosen preference unless a palette sets the background colour. ### Palette Paste a colour list or a [Coolors](https://coolors.co) palette link. Colours have roles by position: | Position | Role | |---|---| | 1 | background | | 2 | widget surface | | 3 | primary controls and first chart line | | 4 | accent | | 5 | text | | 6+ | additional chart lines | Missing roles are derived, so three colours are enough to get started. **Rotate** shifts their order. Text contrast is corrected automatically; failure and success indicators keep their status colours. ### Background and lock Background draws an image beneath the widgets. Lock disables publishing from controls and shows **Read-only** when viewing the dashboard. It does not restrict API permissions and does not disable controls in edit mode. ## Showing one Open `/view/{name}` for a dashboard-only view with your normal session. For a dedicated screen, pair a panel. ## Panels: hanging a screen on a wall As a superuser: 1. Open **Dashboards → Panels**, add a panel and select its dashboards. 2. Enable **Touch friendly** for larger controls. 3. Open the displayed pairing link on the device. It shows a six-character code. 4. Enter that code for the panel, check the device description, then press **Pair device**. The screen collects its credential and shows the assigned published dashboards. Several dashboards get a navigation rail. A panel credential permits its assigned dashboards, their bound messages and the artifacts they show. It also permits publishing from its controls and query charts. **Lock** changes the viewing surface; it does not narrow the credential. **Unpair screen** revokes a locally paired credential and keeps the panel's dashboard assignments. Deleting the panel removes the assignment and its access. !!! note "If the local link is wrong" Pairing links use `FRONTEND_HOST`. Set it to the app address reachable from the screen's network. ### A screen somewhere you cannot reach An [enrolled instance](portal.md) also shows a portal pairing link. Use that link on the remote screen, then approve its code in the same dialog. The device description says *via portal*. The instance enforces the same dashboard and message limits. Remote credentials are issued by the portal, so **Unpair screen** does not revoke them; revoke them at the portal. Deleting the panel removes access on the instance. ## See also - [Payload types](../reference/payload-types.md) - [Flows, nodes and messages](../concepts/flows.md) - [Accounts and the portal](portal.md)