# Dashboards A dashboard is a place to see your work at a glance and jump straight back into it. Notes, plans, and canvases hold the work. A dashboard sits above them and answers a different question: what should I look at right now, and where do I go next. Instead of opening five items to check on a project, you build one view that surfaces the parts that matter and links straight back to the source. ## When to reach for a dashboard - a project overview that pulls its notes, tasks, and files into one place - a personal command center you open first thing: what is due, what you touched last, what is next - a status page for work in motion, so you never have to go digging to know where things stand - a launchpad of links to the handful of items you return to every day ## Home is already a dashboard The Home screen is a dashboard Undra ships for you. It is not a special hard-coded page: it is built from the same widgets you can add yourself, so anything Home does, your own dashboards can do too. Use Home as it comes, reshape it, or build dedicated dashboards alongside it. Out of the box, Home greets you, shows what is **due** and what you **recently opened**, offers a row of **quick actions** to create items, counts your workspace at a glance, and draws an **activity heatmap** of your edits. From its toolbar you can also open **Milestones**, an optional "learn by doing" board that marks off Undra capabilities as you grow into them. Customise Home from the gear in its corner, and save layouts as templates to switch between. ## What you can put on a dashboard Each tile is a widget. You drop them on a grid and size them to taste. | Widget | What it shows | |---|---| | **Text** | A heading, paragraph, or note written in Markdown | | **Query list** | Live rows pulled from your workspace | | **Chart** | Counts bucketed by a field, drawn as bars | | **Graph** | A set of items shown as a connected node graph | | **Link** | A button that jumps to a route or a specific item | | **Image** | A picture, with an optional title overlay | | **Clock** | The live time of day | | **Script** | Custom output for anything the built-ins do not cover | The **Query list** is the workhorse, and it gets its own section below. Here is when to reach for each of the others: - **Chart**: when you want a count broken down by a field rather than a list of rows. Reach for it to answer "how many notes per tag" or "how many tasks created each week," where a single shape tells the story faster than reading rows. - **Graph**: when the relationships matter more than the list. Reach for it to see a project's notes and tasks as connected dots, so you can spot what clusters together and what stands alone. - **Link**: when you keep opening the same one place. Reach for it to pin a button to a specific item or a route (your active plan, the Calendar, a canvas you live in) so it is one click from the dashboard. - **Image**: when a view needs a banner or a cover. Reach for it to put a project hero image or a labelled photo at the top of the board, with an optional title laid over it. - **Clock**: when the dashboard is a wall view or a daily landing page. Reach for it to show the live time and date, so a board you leave open doubles as an at-a-glance status screen. - **Script**: when none of the above fit and you need a computed answer. Reach for it to turn workspace data into a number, a sentence, or a small table the built-in widgets cannot produce. See [The Script widget runs your own code](#script) below. ## Query lists read your live workspace The query list is the widget that makes a dashboard feel alive. You point it at a source (your notes, plans, tasks, canvases, other dashboards, recently opened items, or everything), choose how to sort, and cap how many rows to show. It reads the real workspace every time, so a panel like "Upcoming plans" or "Recent notes" stays current on its own. You are not copying items onto the dashboard, you are opening a live window onto them. ## The Script widget runs your own code {#script} The Script widget is the escape hatch: when no built-in widget produces the answer you want, you write a small piece of JavaScript and the widget renders whatever it returns. It is the deepest widget on the board, so it is worth a closer look. **What it runs.** Your code must define an entry point named `main` that receives a context object: ```javascript async function main(ctx) { const tasks = await ctx.query.run({ source: 'tasks', sort: [{ field: 'due', dir: 'asc' }], limit: 50, }) return `**${tasks.length}** tasks on the board` } ``` `main` can be `async` (as above) or a plain function. **Whatever it returns is the widget's output.** Return a Markdown string and the widget renders it as formatted text, the same Markdown you write in notes. Return an object of the form `{ markdown, title?, refreshMs? }` when you want a title or a periodic refresh interval as well. Anything else is treated as an error. **What `ctx` gives you.** The context object is a small, fixed surface, not a general programming environment: - `ctx.query.run(spec)`: run a workspace query and get back the matching rows. This is the **same query engine the Query list widget uses**, so the source/sort/limit shape you see in the file example below works here too. This is how a script reads your live workspace. - `ctx.storage.get(key)` / `ctx.storage.set(key, value)`: stash a small value for this widget between runs (scoped to this one widget). - `ctx.time.now()`: the current time as an ISO string. - `ctx.nav.open(target)`: jump the app to an item or a route, the same kinds of targets the Link widget uses. - `ctx.input`: an optional value you save with the widget and read back inside the script, so you can reuse one script with different settings. **The sandbox.** Scripts run in a sandboxed background worker, isolated from the rest of the app. **There is no network access**: `fetch`, `XMLHttpRequest`, and `WebSocket` are switched off, so a script cannot call out to the internet. It cannot reach into other items except through the `ctx` surface above. Each run has a **ten-second time limit** and is stopped if it overruns. The output is rendered as Markdown through Undra's safe renderer, so a script cannot inject arbitrary HTML or scripts into your dashboard. That combination (your data in, Markdown out, no network, short time limit) is deliberate: a Script widget is for computing a small answer from your own workspace, not for running a service. :::note A different `ctx` from extensions The `ctx` a Script widget receives is **not** the same `ctx` an extension's `activate(ctx)` gets. They share a name but are separate surfaces: extensions get the full runtime and read/write workspace APIs documented on the [ctx API](/docs/extensions/ctx-api/) page, while a Script widget gets only the small read-and-render surface listed above. If you need to register new UI, item types, or commands, that is an [extension](/docs/extensions/), not a Script widget. ::: ## Lay it out on a grid Dashboards use a twelve-column grid. Drag a widget to move it, drag an edge to resize, and the grid keeps everything aligned. A full-width banner spans all twelve columns, a sidebar list might take five, three small counters sit four across. The shape is yours. ## Under the hood A dashboard is a single file (`.udash`) you own. Each widget records its type, its position on the grid, and its own small config. Here is a real query-list widget from the Home dashboard, trimmed to the parts that matter: ```file="Home.udash" { "id": "w-home-open-tasks", "type": "queryList", "layout": { "x": 0, "y": 12, "w": 7, "h": 9 }, "queryList": { "queryList": { "title": "Upcoming plans", "query": { "source": "tasks", "sort": [{ "field": "due", "dir": "asc" }], "limit": 12 }, "view": { "mode": "cards", "cardSize": "s" } } } } ``` The `query` is the whole idea: pull tasks, sort by due date, show the next twelve. Change the source or the sort and the tile shows something else, with nothing to copy by hand. The same `query` shape is what a Script widget passes to `ctx.query.run`. :::tip Start from the one you have The fastest way to learn dashboards is to reshape Home. Right-click a widget to inspect it, drag an edge to resize, and add a query list pointed at your own notes. The point of a dashboard is to route you back into real items, so keep it short and cut any tile that is not helping you decide what to do next. ::: ## Where to go next - **[Plans](/docs/workspace/plans/)**: feed the task and due-date widgets. - **[Notes](/docs/workspace/notes/)** and **[Canvas](/docs/workspace/canvas/)**: what your query lists and links point back to. - **[Search](/docs/undraverse/search/)**: slice your workspace for a one-off answer instead of a saved view.