Skip to content

Commit 8f1aed3

Browse files
committed
Add README for plain.toolbar
1 parent da37a78 commit 8f1aed3

File tree

2 files changed

+222
-34
lines changed

2 files changed

+222
-34
lines changed

plain-toolbar/README.md

Lines changed: 0 additions & 34 deletions
This file was deleted.

plain-toolbar/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
plain/toolbar/README.md
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# plain.toolbar
2+
3+
**A developer toolbar that displays debugging information in your browser.**
4+
5+
- [Overview](#overview)
6+
- [Built-in panels](#built-in-panels)
7+
- [Request panel](#request-panel)
8+
- [Exception panel](#exception-panel)
9+
- [Creating custom toolbar items](#creating-custom-toolbar-items)
10+
- [Button-only items](#button-only-items)
11+
- [Visibility](#visibility)
12+
- [JavaScript API](#javascript-api)
13+
- [FAQs](#faqs)
14+
- [Installation](#installation)
15+
16+
## Overview
17+
18+
The toolbar appears at the bottom of your browser window and shows useful debugging information about the current request. You can expand it to see detailed panels, switch between tabs, and resize it by dragging the top edge.
19+
20+
To render the toolbar, add the `{% toolbar %}` tag to your base template (typically just before the closing `</body>` tag):
21+
22+
```html
23+
<!DOCTYPE html>
24+
<html>
25+
<head>
26+
<title>My App</title>
27+
</head>
28+
<body>
29+
{% block content %}{% endblock %}
30+
31+
{% toolbar %}
32+
</body>
33+
</html>
34+
```
35+
36+
The toolbar automatically hides itself in production unless the user is an admin. In debug mode, it always appears.
37+
38+
## Built-in panels
39+
40+
### Request panel
41+
42+
The Request panel shows information about the current HTTP request:
43+
44+
- Request ID
45+
- Query parameters
46+
- HTTP method
47+
- View class
48+
- URL pattern, name, args, and kwargs
49+
- Template names (if available)
50+
- Primary object (if the view has an `object` attribute)
51+
52+
### Exception panel
53+
54+
When an exception occurs during request handling, the Exception panel automatically appears with:
55+
56+
- The exception type and message
57+
- A color-coded traceback showing frames from your app, Plain, third-party packages, and Python stdlib
58+
- Source code context around each frame (expandable/collapsible)
59+
- Local variables for each frame (in debug mode)
60+
- A "Copy" button to copy the full exception for sharing
61+
- A "View raw" button to see the standard Python traceback format
62+
- Clickable file paths that open in VS Code
63+
64+
App frames are highlighted in amber and expanded by default, making it easy to spot where the error occurred in your code.
65+
66+
## Creating custom toolbar items
67+
68+
You can add your own panels to the toolbar by creating a `ToolbarItem` subclass and registering it with the `@register_toolbar_item` decorator.
69+
70+
Create a `toolbar.py` file in any installed app:
71+
72+
```python
73+
# app/users/toolbar.py
74+
from plain.toolbar import ToolbarItem, register_toolbar_item
75+
76+
77+
@register_toolbar_item
78+
class UserToolbarItem(ToolbarItem):
79+
name = "User"
80+
panel_template_name = "toolbar/user.html"
81+
82+
def get_template_context(self):
83+
context = super().get_template_context()
84+
context["current_user"] = getattr(self.request, "user", None)
85+
return context
86+
```
87+
88+
Then create the panel template:
89+
90+
```html
91+
<!-- app/users/templates/toolbar/user.html -->
92+
<div class="px-6 py-4 text-sm">
93+
{% if current_user %}
94+
<dl class="grid grid-cols-[max-content_1fr] gap-x-8 gap-y-2">
95+
<dt>Email</dt>
96+
<dd class="text-white/50">{{ current_user.email }}</dd>
97+
<dt>ID</dt>
98+
<dd class="text-white/50">{{ current_user.id }}</dd>
99+
</dl>
100+
{% else %}
101+
<p class="text-white/50">No user logged in</p>
102+
{% endif %}
103+
</div>
104+
```
105+
106+
The toolbar uses autodiscovery to find `toolbar.py` files in all installed apps.
107+
108+
### Button-only items
109+
110+
You can also create toolbar items that only show a button in the minimized toolbar bar (no expandable panel). Set `button_template_name` instead of `panel_template_name`:
111+
112+
```python
113+
@register_toolbar_item
114+
class QuickActionToolbarItem(ToolbarItem):
115+
name = "QuickAction"
116+
button_template_name = "toolbar/quick_action_button.html"
117+
118+
def is_enabled(self):
119+
# Only show when a certain condition is met
120+
return some_condition
121+
```
122+
123+
Override `is_enabled()` to control when your toolbar item appears.
124+
125+
## Visibility
126+
127+
The toolbar only renders when `Toolbar.should_render()` returns `True`. This happens when:
128+
129+
1. `DEBUG` is `True`, or
130+
2. The user has `is_admin = True`, or
131+
3. An admin is impersonating another user (requires `plain.admin`)
132+
133+
You can also temporarily hide the toolbar:
134+
135+
- Click the X button to hide it for the current session
136+
- Click the clock icon to hide it for 1 hour (stored in localStorage)
137+
- Call `plainToolbar.show()` in the browser console to bring it back
138+
139+
## JavaScript API
140+
141+
The toolbar exposes a `window.plainToolbar` object for programmatic control:
142+
143+
```javascript
144+
// Show/hide the toolbar
145+
plainToolbar.show();
146+
plainToolbar.hide();
147+
148+
// Expand/collapse the details panel
149+
plainToolbar.expand();
150+
plainToolbar.collapse();
151+
plainToolbar.toggleExpand();
152+
153+
// Show a specific tab
154+
plainToolbar.showTab("Request");
155+
plainToolbar.showTab("Exception");
156+
157+
// Hide for a duration (milliseconds from now)
158+
plainToolbar.hideUntil(Date.now() + 3600000); // Hide for 1 hour
159+
160+
// Reset custom height
161+
plainToolbar.resetHeight();
162+
```
163+
164+
## FAQs
165+
166+
#### How do I style my custom panel?
167+
168+
The toolbar uses Tailwind CSS classes. Your panel template has access to all Tailwind utilities. The toolbar has a dark theme, so use light text colors like `text-white`, `text-stone-300`, or `text-white/50` for muted text.
169+
170+
#### Can I add multiple custom panels?
171+
172+
Yes. Create multiple `ToolbarItem` subclasses, each with its own `name` and templates. They will appear as separate tabs in the toolbar.
173+
174+
#### Why does the Exception panel open automatically?
175+
176+
When an exception occurs, the toolbar automatically expands and shows the Exception panel so you can immediately see what went wrong. This behavior is intentional to surface errors quickly during development.
177+
178+
#### How do I disable the toolbar completely?
179+
180+
Remove `plain.toolbar` from your `INSTALLED_PACKAGES` setting. Alternatively, remove the `{% toolbar %}` tag from your templates.
181+
182+
## Installation
183+
184+
Install the `plain.toolbar` package from PyPI:
185+
186+
```console
187+
uv add plain.toolbar
188+
```
189+
190+
Add `plain.toolbar` to your `INSTALLED_PACKAGES` in `app/settings.py`:
191+
192+
```python
193+
INSTALLED_PACKAGES = [
194+
# ... other packages
195+
"plain.toolbar",
196+
]
197+
```
198+
199+
Add the `{% toolbar %}` template tag to your base template, just before the closing `</body>` tag:
200+
201+
```html
202+
<!DOCTYPE html>
203+
<html>
204+
<head>
205+
<title>My App</title>
206+
</head>
207+
<body>
208+
{% block content %}{% endblock %}
209+
210+
{% toolbar %}
211+
</body>
212+
</html>
213+
```
214+
215+
A `VERSION` setting is required in your `app/settings.py` to display in the toolbar:
216+
217+
```python
218+
VERSION = "1.0.0"
219+
```
220+
221+
The toolbar should now appear at the bottom of your browser window in debug mode.

0 commit comments

Comments
 (0)