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 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
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:
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.
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 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, 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:
{
"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.
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.