---
title: Admin UI
description: A dashboard for every collection, and for running the server, at /_/.
section: Operations
order: 2
---

# Admin UI

<p class="lead">Every Sluurp server has a dashboard at <code>/_/</code>, like Django's admin: made from your schema, with nothing to write. Each collection gets a table to browse, filter and edit, and the server gets the screens to run it.</p>

## For your data

- **A table per collection,** with a filter box (`paid = true && total > 100`), sorting, column choice and pages.
- **A form per record** that fits each field: a date picker for dates, a searchable picker for relations, an image preview and upload for files.
- **History and undo:** every change with who and why, any version brought back, deleted records in a recycle bin.
- **Explore and pivot tables,** charts and formulas over a collection, without exporting it.
- **Rules** for who may read and write, written next to the collection.

## For the server

Logs, an SQL console, backups, scheduled jobs, rate limits, mail, sign-in providers, payments, forms, feeds, translations and storage, each a screen. Drag the Platform rows into your own order, or move one with Alt and an arrow key.

## Components

The **Components** screen is the kit's workshop, like [Storybook](https://storybook.js.org). Each component is drawn alone on a canvas, at a phone's width, a tablet's or the full width, in light or dark. You can change its arguments in **Controls** and copy the code for what's on show from **Code**. **Docs** is a page per component: what it's for, a table of its arguments, and every story drawn under it.

Stories are Storybook's own [Component Story Format](https://storybook.js.org/docs/api/csf) (CSF 3), so a story file moves between the two unchanged. A file named `*.stories.tsx` next to a component is found by its name, with no config:

```tsx title="client/kit/button.stories.tsx"
import { Button } from "./button.js";

export default {
  title: "Actions/Button",
  component: Button,
  args: { children: "Save changes", disabled: false },
  argTypes: { variant: { control: "select", options: ["default", "outline", "destructive"] } },
};

export const Primary = {};
export const Destructive = { args: { variant: "destructive", children: "Delete" } };
```

With no `render`, a story is `component(args)`. A kit component takes one object of props, as a story's args are. Controls are inferred from each arg's value; `argTypes` is only needed for a choice. A `play({ canvasElement, args })` function runs once the story is drawn.

One addition of Sluurp's own, which Storybook ignores: `argTypes: { collection: { control: "collection" } }` picks a collection of the open project, and its rows reach `render(args, { loaded: { rows } })`. A select, a table or a list is then drawn from real data, with this project's words and lengths rather than three made-up ones. Every story is drawn in a test.

## Compared with Django admin

**What Sluurp has that Django admin does not:**

- Live updates: a record someone else changes changes on your screen.
- History, restore and a recycle bin for every collection, built in.
- An SQL console, backups, logs, jobs and rate limits in the same place.
- Nothing to register or configure: a collection is in the admin as soon as it exists.
- Translations edited live, with several people at once.

**What Django admin has that Sluurp does not yet:**

- Customising a model's admin in code: which columns show, how the form is grouped, read-only fields per screen.
- Your own bulk actions, written in code, on the ticked rows.
- Editing related records inside the parent's form (inlines).
- A date drill-down (years, then months, then days) above a list.

The admin UI is built with the same [UI kit](/docs/ui-kit) your app can use.
