You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -52,7 +52,7 @@ The only runtime dependency is Django. `dj-control-room` is optional and only ne
52
52
53
53
### Panel tools
54
54
55
-
`PanelConfig` accepts an optional `tools` list of `PanelTool` instances. Each tool carries a name, a scope (reusing the same permission system as views), a human-readable description, a JSON Schema for its inputs, and a handler callable. When installed panels expose tools, the `dj-control-room` hub aggregates them across all panels, filters by the current user's permissions at request time, and dispatches calls through a unified endpoint — suitable for AI agent integrations and an in-admin chat experience with no per-panel HTTP wiring required.
55
+
`PanelConfig` accepts an optional `tools` list of `PanelTool` instances. Each tool carries a name, a scope (reusing the same permission system as views), a human-readable description, a JSON Schema for its inputs, and a handler callable. When installed panels expose tools, the `dj-control-room` hub aggregates them across all panels, filters by the current user's permissions at request time, and dispatches calls through a unified endpoint, suitable for AI agent integrations and an in-admin chat experience with no per-panel HTTP wiring required.
56
56
57
57
## Screenshots
58
58
@@ -177,7 +177,7 @@ DJ_MY_PANEL_SETTINGS = {
177
177
}
178
178
```
179
179
180
-
`themes/unfold.css`remaps DCR's accent/surface/border/muted tokens to [django-unfold](https://github.com/unfoldadmin/django-unfold)'s own CSS variables (`--color-primary-*`, `--color-base-*`, `--color-font-*`), so panels match the host site's configured brand color. `themes/jazzmin.css` does the same for [django-jazzmin](https://github.com/farridav/django-jazzmin), mapping onto Bootstrap 5's `--bs-primary`, `--bs-body-*`, and `--bs-border-color` variables so panels track whichever Bootswatch theme Jazzmin is configured with. See the [configuration docs](https://django-control-room.github.io/dj-control-room-base/configuration/#theme-adapters) for details.
180
+
`themes/unfold.css`matches panels to your [django-unfold](https://github.com/unfoldadmin/django-unfold) brand color, and `themes/jazzmin.css` does the same for [django-jazzmin](https://github.com/farridav/django-jazzmin), tracking whichever Bootswatch theme it's configured with. See the [configuration docs](https://django-control-room.github.io/dj-control-room-base/configuration/#theme-adapters) for details, or [Theme Adapters](https://django-control-room.github.io/dj-control-room-base/themes/) for a visual gallery.
Copy file name to clipboardExpand all lines: docs/building-panels.md
+11-11Lines changed: 11 additions & 11 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -201,13 +201,13 @@ The base template automatically handles `dj_cr_load_default_css` and `dj_cr_extr
201
201
202
202
Panel tools are optional, structured callables that the `dj-control-room` hub can aggregate across all installed panels and expose through a unified API. They are designed to power AI agent integrations (where an LLM calls tools on your behalf) and an in-admin chat experience, but they are generic enough to be used in any context that needs a structured, permission-aware callable.
203
203
204
-
Tools reuse the same scope-based permission system as views — no separate permission wiring is needed.
204
+
Tools reuse the same scope-based permission system as views, so no separate permission wiring is needed.
205
205
206
206
### Tool primitives
207
207
208
208
All four are importable from `dj_control_room_base.core.panel_tool`:
209
209
210
-
**`PanelTool`**— the tool definition. You'll rarely construct this directly (see `ToolRegistry` below), but it's what ends up on `PanelConfig.tools`:
210
+
**`PanelTool`**- the tool definition. You'll rarely construct this directly (see `ToolRegistry` below), but it's what ends up on `PanelConfig.tools`:
211
211
212
212
| Field | Type | Description |
213
213
|---|---|---|
@@ -217,27 +217,27 @@ All four are importable from `dj_control_room_base.core.panel_tool`:
217
217
|`input_schema`|`dict`|[JSON Schema](https://json-schema.org) object describing the tool's input arguments. Tools that take no arguments should use `{"type": "object", "properties": {}}`. |
218
218
|`handler`|`Callable`| A function that receives a `PanelToolContext` and returns a `PanelToolResult`. |
219
219
220
-
**`PanelToolContext`**— passed to the handler at call time:
220
+
**`PanelToolContext`**- passed to the handler at call time:
221
221
222
222
| Field | Type | Description |
223
223
|---|---|---|
224
224
|`user`|`Any`| The Django `User` object of the caller. |
225
225
|`inputs`|`dict`| The validated input arguments for this call, matching the tool's `input_schema`. |
226
226
|`config`|`Any`| The panel's `PanelConfig` instance, injected by the hub dispatcher. |
227
227
228
-
**`PanelToolResult`**— returned by the handler:
228
+
**`PanelToolResult`**- returned by the handler:
229
229
230
230
| Field | Type | Description |
231
231
|---|---|---|
232
232
|`success`|`bool`| Whether the tool call succeeded. |
233
233
|`message`|`str`| A short human-readable summary of the outcome. |
234
234
|`data`|`dict`| The structured result payload. Defaults to `{}`. |
235
235
236
-
**`ToolRegistry`**— collects `PanelTool`s via a `@registry.register(...)` decorator, so each tool's metadata lives directly above the handler it describes instead of in a separate list you have to keep in sync. This is the recommended way to define tools (see below).
236
+
**`ToolRegistry`**- collects `PanelTool`s via a `@registry.register(...)` decorator, so each tool's metadata lives directly above the handler it describes instead of in a separate list you have to keep in sync. This is the recommended way to define tools (see below).
237
237
238
238
### Defining tools
239
239
240
-
Keep handlers in a dedicated `tools.py` module. Use local imports inside handlers for anything that touches Django models — this keeps the module safe to import at any point in the Django startup sequence.
240
+
Keep handlers in a dedicated `tools.py` module. Use local imports inside handlers for anything that touches Django models, which keeps the module safe to import at any point in the Django startup sequence.
241
241
242
242
Instantiate one `ToolRegistry` per `tools.py` module and decorate each handler with `@registry.register(...)`:
The decorator only records metadata as a side effect — it returns the handler unchanged, so `handle_get_item` and `handle_list_items` remain plain, directly callable functions (e.g. in tests, just call `handle_get_item(ctx)`).
299
+
The decorator only records metadata as a side effect: it returns the handler unchanged, so `handle_get_item` and `handle_list_items` remain plain, directly callable functions (e.g. in tests, just call `handle_get_item(ctx)`).
300
300
301
301
### Registering tools on `PanelConfig`
302
302
@@ -320,7 +320,7 @@ Panel authors do not need to write any URL configuration for tools as this will
320
320
321
321
#### Building the list manually
322
322
323
-
`ToolRegistry` is a convenience, not a requirement —`PanelConfig(tools=...)` just needs a `list[PanelTool]`. If you'd rather construct `PanelTool` instances directly (e.g. building the list programmatically from some other source), that still works:
323
+
`ToolRegistry` is a convenience, not a requirement -`PanelConfig(tools=...)` just needs a `list[PanelTool]`. If you'd rather construct `PanelTool` instances directly (e.g. building the list programmatically from some other source), that still works:
324
324
325
325
```python
326
326
from dj_control_room_base.core.panel_tool import PanelTool
@@ -399,7 +399,7 @@ That is the full wiring. One `PanelConfig` declaration in `conf.py` gives all vi
399
399
|---|---|---|
400
400
|`get_url_name()`|`"index"`| URL name for the panel's main view. The hub resolves `reverse(f"{app_name}:{get_url_name()}")`. |
401
401
|`get_config()`|`None`| Return the panel's `PanelConfig` instance. Override using a local import (see above). |
402
-
|`validate()`|—| Assert all required attributes are set. Convenience method for tests; the registry runs its own validation at autodiscovery time. |
402
+
|`validate()`|n/a| Assert all required attributes are set. Convenience method for tests; the registry runs its own validation at autodiscovery time. |
403
403
404
404
---
405
405
@@ -433,7 +433,7 @@ Returns `True` if the request's user may access the panel or a specific scope. T
Returns `True` if `user` may access the panel or a specific scope. Operates on a user object directly so it can be called outside of a request context — for example in tool dispatch, management commands, or background tasks.
436
+
Returns `True` if `user` may access the panel or a specific scope. Operates on a user object directly so it can be called outside of a request context, for example in tool dispatch, management commands, or background tasks.
Copy file name to clipboardExpand all lines: docs/configuration.md
+1-5Lines changed: 1 addition & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -101,11 +101,7 @@ Currently available:
101
101
|`themes/unfold.css`| Projects using [django-unfold](https://github.com/unfoldadmin/django-unfold) as their admin skin. |
102
102
|`themes/jazzmin.css`| Projects using [django-jazzmin](https://github.com/farridav/django-jazzmin) as their admin skin. |
103
103
104
-
`themes/unfold.css` remaps a handful of `--dcr-*` tokens (accent color, surfaces, borders, muted text) to Unfold's own `--color-primary-*` / `--color-base-*` / `--color-font-*` CSS variables, so panels pick up the host site's configured brand color instead of DCR's classic-admin blue. It only touches tokens - never `dcr-*` component rules - and every override falls back to DCR's own default if the Unfold variable isn't present, so it's safe to load even if Unfold changes its internals in a future release. Semantic status colors (success/warning/danger/info) are left alone, since Unfold doesn't expose those as configurable brand colors.
105
-
106
-
`themes/jazzmin.css` follows the same approach for Jazzmin's Bootstrap 5 foundation, remapping the same set of tokens to `--bs-body-color`, `--bs-border-color`, `--bs-secondary-color`, `--bs-tertiary-bg`, `--bs-primary`, and `--bs-primary-bg-subtle` - so panels track whatever Bootswatch theme is configured via `JAZZMIN_UI_TWEAKS["theme"]` instead of hardcoding one palette. Same fallback safety and same scope (tokens only, no `dcr-*` component rules, semantic status colors untouched).
107
-
108
-
Both adapters rely on `design-system.css` already recognizing the host skin's dark-mode signal so the *default* DCR palette (not just the adapter's own overrides) switches correctly: Unfold toggles a plain `dark` class on `<html>`, while Jazzmin (via Bootstrap 5) sets `data-bs-theme="dark"` on `<html>`. Both are handled automatically - no extra configuration needed beyond loading the adapter's stylesheet.
104
+
`themes/unfold.css` maps DCR's tokens onto [django-unfold](https://github.com/unfoldadmin/django-unfold)'s own CSS variables, so panels automatically pick up the host site's configured brand color. `themes/jazzmin.css` does the same for [django-jazzmin](https://github.com/farridav/django-jazzmin), tracking whichever Bootswatch theme (light or dark) is configured via `JAZZMIN_UI_TWEAKS["theme"]`. Both only touch tokens, never `dcr-*` component rules, and dark mode is handled automatically - no extra configuration needed beyond loading the stylesheet.
109
105
110
106
Because this is opt-in per panel rather than hub-wide, each panel you want themed needs its own `EXTRA_CSS` entry for now.
Copy file name to clipboardExpand all lines: docs/index.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -41,7 +41,7 @@ Panels register themselves with Control Room via a `pyproject.toml` entry point
41
41
42
42
### Panel tools
43
43
44
-
`PanelConfig` accepts an optional `tools` list of `PanelTool` instances. Each tool declares a name, a scope (reusing the same permission system as views), a description, a JSON Schema for its inputs, and a handler callable. When a panel exposes tools, the `dj-control-room` hub aggregates them into a central registry, filters by user permissions, and dispatches calls through a unified endpoint — enabling AI agent integrations and an in-admin chat experience without any per-panel HTTP wiring. See [Building Panels — Panel Tools](building-panels.md#panel-tools) for the full guide.
44
+
`PanelConfig` accepts an optional `tools` list of `PanelTool` instances. Each tool declares a name, a scope (reusing the same permission system as views), a description, a JSON Schema for its inputs, and a handler callable. When a panel exposes tools, the `dj-control-room` hub aggregates them into a central registry, filters by user permissions, and dispatches calls through a unified endpoint, enabling AI agent integrations and an in-admin chat experience without any per-panel HTTP wiring. See [Building Panels - Panel Tools](building-panels.md#panel-tools) for the full guide.
Copy file name to clipboardExpand all lines: docs/themes.md
+3-3Lines changed: 3 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -30,7 +30,7 @@ DJ_MY_PANEL_SETTINGS = {
30
30
31
31
## django-jazzmin
32
32
33
-
[`django-jazzmin`](https://github.com/farridav/django-jazzmin) is built on Bootstrap 5 and ships as a set of [Bootswatch](https://bootswatch.com/) skins, selected via `JAZZMIN_UI_TWEAKS["theme"]`. `themes/jazzmin.css` maps the same DCR tokens onto Bootstrap's `--bs-*` variables (`--bs-primary`, `--bs-body-*`, `--bs-border-color`, `--bs-secondary-color`, ...), with per-theme accent and dark-mode fallbacks sourced from each Bootswatch palette - so panels track whichever theme is active without any extra configuration.
33
+
[`django-jazzmin`](https://github.com/farridav/django-jazzmin) is built on Bootstrap 5 and ships as a set of [Bootswatch](https://bootswatch.com/) skins, selected via `JAZZMIN_UI_TWEAKS["theme"]`. `themes/jazzmin.css` maps DCR's tokens onto Bootstrap's own CSS variables, so panels track whichever theme is active, including Jazzmin's dark skins, without any extra configuration.
34
34
35
35
```python
36
36
DJ_MY_PANEL_SETTINGS= {
@@ -46,10 +46,10 @@ All of Jazzmin's built-in Bootswatch themes are covered, each with its own accen
Dark themes are detected via the `body.theme-<name>` class Jazzmin applies (not `data-bs-theme`, which Jazzmin doesn't document or set) - see [`ui_customisation`](https://django-jazzmin.readthedocs.io/ui_customisation/) for the full list Jazzmin ships.
49
+
See [`ui_customisation`](https://django-jazzmin.readthedocs.io/ui_customisation/) for the full list of themes Jazzmin ships.
50
50
51
51
---
52
52
53
53
## Build your own
54
54
55
-
Both adapters follow the same recipe: remap `--dcr-*` tokens to the host skin's variables, fall back to DCR's own defaults when a variable is missing, and leave semantic status colors (success/warning/danger/info) untouched since most skins don't expose those as configurable brand colors. This works well for any Tailwind CSS or Bootstrap admin skin that exposes its palette as CSS custom properties - use `unfold.css` or `jazzmin.css` as a starting point.
55
+
Both adapters follow the same recipe: remap `--dcr-*` tokens to the host skin's own variables, with sensible fallbacks. This works well for any Tailwind CSS or Bootstrap admin skin that exposes its palette as CSS custom properties - use `unfold.css` or `jazzmin.css` as a starting point.
0 commit comments