plain.toolbar 0.10.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- plain_toolbar-0.10.0/.gitignore +21 -0
- plain_toolbar-0.10.0/LICENSE +28 -0
- plain_toolbar-0.10.0/PKG-INFO +233 -0
- plain_toolbar-0.10.0/README.md +1 -0
- plain_toolbar-0.10.0/plain/toolbar/CHANGELOG.md +190 -0
- plain_toolbar-0.10.0/plain/toolbar/README.md +221 -0
- plain_toolbar-0.10.0/plain/toolbar/__init__.py +4 -0
- plain_toolbar-0.10.0/plain/toolbar/assets/toolbar/toolbar.js +208 -0
- plain_toolbar-0.10.0/plain/toolbar/config.py +10 -0
- plain_toolbar-0.10.0/plain/toolbar/exceptions.py +153 -0
- plain_toolbar-0.10.0/plain/toolbar/registry.py +30 -0
- plain_toolbar-0.10.0/plain/toolbar/templates/toolbar/exception.html +161 -0
- plain_toolbar-0.10.0/plain/toolbar/templates/toolbar/exception_button.html +5 -0
- plain_toolbar-0.10.0/plain/toolbar/templates/toolbar/request.html +50 -0
- plain_toolbar-0.10.0/plain/toolbar/templates/toolbar/toolbar.html +86 -0
- plain_toolbar-0.10.0/plain/toolbar/templates.py +20 -0
- plain_toolbar-0.10.0/plain/toolbar/toolbar.py +113 -0
- plain_toolbar-0.10.0/pyproject.toml +21 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.venv
|
|
2
|
+
/.env
|
|
3
|
+
*.egg-info
|
|
4
|
+
*.py[co]
|
|
5
|
+
__pycache__
|
|
6
|
+
*.DS_Store
|
|
7
|
+
|
|
8
|
+
/*.code-workspace
|
|
9
|
+
|
|
10
|
+
# Test apps
|
|
11
|
+
plain*/tests/.plain
|
|
12
|
+
|
|
13
|
+
# Agent scratch files
|
|
14
|
+
/scratch
|
|
15
|
+
|
|
16
|
+
# Plain temp dirs
|
|
17
|
+
.plain
|
|
18
|
+
|
|
19
|
+
.vscode
|
|
20
|
+
/.claude/skills/plain-*
|
|
21
|
+
/.benchmarks
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023, Dropseed, LLC
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plain.toolbar
|
|
3
|
+
Version: 0.10.0
|
|
4
|
+
Summary: Debug toolbar for Plain applications
|
|
5
|
+
Author-email: Dave Gaeddert <dave.gaeddert@dropseed.dev>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.13
|
|
9
|
+
Requires-Dist: plain-tailwind<1.0.0
|
|
10
|
+
Requires-Dist: plain<1.0.0
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
|
|
13
|
+
# plain.toolbar
|
|
14
|
+
|
|
15
|
+
**A developer toolbar that displays debugging information in your browser.**
|
|
16
|
+
|
|
17
|
+
- [Overview](#overview)
|
|
18
|
+
- [Built-in panels](#built-in-panels)
|
|
19
|
+
- [Request panel](#request-panel)
|
|
20
|
+
- [Exception panel](#exception-panel)
|
|
21
|
+
- [Creating custom toolbar items](#creating-custom-toolbar-items)
|
|
22
|
+
- [Button-only items](#button-only-items)
|
|
23
|
+
- [Visibility](#visibility)
|
|
24
|
+
- [JavaScript API](#javascript-api)
|
|
25
|
+
- [FAQs](#faqs)
|
|
26
|
+
- [Installation](#installation)
|
|
27
|
+
|
|
28
|
+
## Overview
|
|
29
|
+
|
|
30
|
+
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.
|
|
31
|
+
|
|
32
|
+
To render the toolbar, add the `{% toolbar %}` tag to your base template (typically just before the closing `</body>` tag):
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<!DOCTYPE html>
|
|
36
|
+
<html>
|
|
37
|
+
<head>
|
|
38
|
+
<title>My App</title>
|
|
39
|
+
</head>
|
|
40
|
+
<body>
|
|
41
|
+
{% block content %}{% endblock %}
|
|
42
|
+
|
|
43
|
+
{% toolbar %}
|
|
44
|
+
</body>
|
|
45
|
+
</html>
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The toolbar automatically hides itself in production unless the user is an admin. In debug mode, it always appears.
|
|
49
|
+
|
|
50
|
+
## Built-in panels
|
|
51
|
+
|
|
52
|
+
### Request panel
|
|
53
|
+
|
|
54
|
+
The Request panel shows information about the current HTTP request:
|
|
55
|
+
|
|
56
|
+
- Request ID
|
|
57
|
+
- Query parameters
|
|
58
|
+
- HTTP method
|
|
59
|
+
- View class
|
|
60
|
+
- URL pattern, name, args, and kwargs
|
|
61
|
+
- Template names (if available)
|
|
62
|
+
- Primary object (if the view has an `object` attribute)
|
|
63
|
+
|
|
64
|
+
### Exception panel
|
|
65
|
+
|
|
66
|
+
When an exception occurs during request handling, the Exception panel automatically appears with:
|
|
67
|
+
|
|
68
|
+
- The exception type and message
|
|
69
|
+
- A color-coded traceback showing frames from your app, Plain, third-party packages, and Python stdlib
|
|
70
|
+
- Source code context around each frame (expandable/collapsible)
|
|
71
|
+
- Local variables for each frame (in debug mode)
|
|
72
|
+
- A "Copy" button to copy the full exception for sharing
|
|
73
|
+
- A "View raw" button to see the standard Python traceback format
|
|
74
|
+
- Clickable file paths that open in VS Code
|
|
75
|
+
|
|
76
|
+
App frames are highlighted in amber and expanded by default, making it easy to spot where the error occurred in your code.
|
|
77
|
+
|
|
78
|
+
## Creating custom toolbar items
|
|
79
|
+
|
|
80
|
+
You can add your own panels to the toolbar by creating a `ToolbarItem` subclass and registering it with the `@register_toolbar_item` decorator.
|
|
81
|
+
|
|
82
|
+
Create a `toolbar.py` file in any installed app:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
# app/users/toolbar.py
|
|
86
|
+
from plain.toolbar import ToolbarItem, register_toolbar_item
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@register_toolbar_item
|
|
90
|
+
class UserToolbarItem(ToolbarItem):
|
|
91
|
+
name = "User"
|
|
92
|
+
panel_template_name = "toolbar/user.html"
|
|
93
|
+
|
|
94
|
+
def get_template_context(self):
|
|
95
|
+
context = super().get_template_context()
|
|
96
|
+
context["current_user"] = getattr(self.request, "user", None)
|
|
97
|
+
return context
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Then create the panel template:
|
|
101
|
+
|
|
102
|
+
```html
|
|
103
|
+
<!-- app/users/templates/toolbar/user.html -->
|
|
104
|
+
<div class="px-6 py-4 text-sm">
|
|
105
|
+
{% if current_user %}
|
|
106
|
+
<dl class="grid grid-cols-[max-content_1fr] gap-x-8 gap-y-2">
|
|
107
|
+
<dt>Email</dt>
|
|
108
|
+
<dd class="text-white/50">{{ current_user.email }}</dd>
|
|
109
|
+
<dt>ID</dt>
|
|
110
|
+
<dd class="text-white/50">{{ current_user.id }}</dd>
|
|
111
|
+
</dl>
|
|
112
|
+
{% else %}
|
|
113
|
+
<p class="text-white/50">No user logged in</p>
|
|
114
|
+
{% endif %}
|
|
115
|
+
</div>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The toolbar uses autodiscovery to find `toolbar.py` files in all installed apps.
|
|
119
|
+
|
|
120
|
+
### Button-only items
|
|
121
|
+
|
|
122
|
+
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`:
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
@register_toolbar_item
|
|
126
|
+
class QuickActionToolbarItem(ToolbarItem):
|
|
127
|
+
name = "QuickAction"
|
|
128
|
+
button_template_name = "toolbar/quick_action_button.html"
|
|
129
|
+
|
|
130
|
+
def is_enabled(self):
|
|
131
|
+
# Only show when a certain condition is met
|
|
132
|
+
return some_condition
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Override `is_enabled()` to control when your toolbar item appears.
|
|
136
|
+
|
|
137
|
+
## Visibility
|
|
138
|
+
|
|
139
|
+
The toolbar only renders when `Toolbar.should_render()` returns `True`. This happens when:
|
|
140
|
+
|
|
141
|
+
1. `DEBUG` is `True`, or
|
|
142
|
+
2. The user has `is_admin = True`, or
|
|
143
|
+
3. An admin is impersonating another user (requires `plain.admin`)
|
|
144
|
+
|
|
145
|
+
You can also temporarily hide the toolbar:
|
|
146
|
+
|
|
147
|
+
- Click the X button to hide it for the current session
|
|
148
|
+
- Click the clock icon to hide it for 1 hour (stored in localStorage)
|
|
149
|
+
- Call `plainToolbar.show()` in the browser console to bring it back
|
|
150
|
+
|
|
151
|
+
## JavaScript API
|
|
152
|
+
|
|
153
|
+
The toolbar exposes a `window.plainToolbar` object for programmatic control:
|
|
154
|
+
|
|
155
|
+
```javascript
|
|
156
|
+
// Show/hide the toolbar
|
|
157
|
+
plainToolbar.show();
|
|
158
|
+
plainToolbar.hide();
|
|
159
|
+
|
|
160
|
+
// Expand/collapse the details panel
|
|
161
|
+
plainToolbar.expand();
|
|
162
|
+
plainToolbar.collapse();
|
|
163
|
+
plainToolbar.toggleExpand();
|
|
164
|
+
|
|
165
|
+
// Show a specific tab
|
|
166
|
+
plainToolbar.showTab("Request");
|
|
167
|
+
plainToolbar.showTab("Exception");
|
|
168
|
+
|
|
169
|
+
// Hide for a duration (milliseconds from now)
|
|
170
|
+
plainToolbar.hideUntil(Date.now() + 3600000); // Hide for 1 hour
|
|
171
|
+
|
|
172
|
+
// Reset custom height
|
|
173
|
+
plainToolbar.resetHeight();
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## FAQs
|
|
177
|
+
|
|
178
|
+
#### How do I style my custom panel?
|
|
179
|
+
|
|
180
|
+
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.
|
|
181
|
+
|
|
182
|
+
#### Can I add multiple custom panels?
|
|
183
|
+
|
|
184
|
+
Yes. Create multiple `ToolbarItem` subclasses, each with its own `name` and templates. They will appear as separate tabs in the toolbar.
|
|
185
|
+
|
|
186
|
+
#### Why does the Exception panel open automatically?
|
|
187
|
+
|
|
188
|
+
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.
|
|
189
|
+
|
|
190
|
+
#### How do I disable the toolbar completely?
|
|
191
|
+
|
|
192
|
+
Remove `plain.toolbar` from your `INSTALLED_PACKAGES` setting. Alternatively, remove the `{% toolbar %}` tag from your templates.
|
|
193
|
+
|
|
194
|
+
## Installation
|
|
195
|
+
|
|
196
|
+
Install the `plain.toolbar` package from PyPI:
|
|
197
|
+
|
|
198
|
+
```console
|
|
199
|
+
uv add plain.toolbar
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Add `plain.toolbar` to your `INSTALLED_PACKAGES` in `app/settings.py`:
|
|
203
|
+
|
|
204
|
+
```python
|
|
205
|
+
INSTALLED_PACKAGES = [
|
|
206
|
+
# ... other packages
|
|
207
|
+
"plain.toolbar",
|
|
208
|
+
]
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Add the `{% toolbar %}` template tag to your base template, just before the closing `</body>` tag:
|
|
212
|
+
|
|
213
|
+
```html
|
|
214
|
+
<!DOCTYPE html>
|
|
215
|
+
<html>
|
|
216
|
+
<head>
|
|
217
|
+
<title>My App</title>
|
|
218
|
+
</head>
|
|
219
|
+
<body>
|
|
220
|
+
{% block content %}{% endblock %}
|
|
221
|
+
|
|
222
|
+
{% toolbar %}
|
|
223
|
+
</body>
|
|
224
|
+
</html>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
A `VERSION` setting is required in your `app/settings.py` to display in the toolbar:
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
VERSION = "1.0.0"
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
The toolbar should now appear at the bottom of your browser window in debug mode.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
plain/toolbar/README.md
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# plain-toolbar changelog
|
|
2
|
+
|
|
3
|
+
## [0.10.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.10.0) (2026-01-15)
|
|
4
|
+
|
|
5
|
+
### What's changed
|
|
6
|
+
|
|
7
|
+
- The toolbar now displays on mobile devices instead of being hidden ([ee7acaa](https://github.com/dropseed/plain/commit/ee7acaa67c))
|
|
8
|
+
- Panel tabs are horizontally scrollable on mobile for better touch navigation ([ee7acaa](https://github.com/dropseed/plain/commit/ee7acaa67c))
|
|
9
|
+
- Panel content area uses a taller height (50vh) on mobile for improved usability ([ee7acaa](https://github.com/dropseed/plain/commit/ee7acaa67c))
|
|
10
|
+
- Resize handle is hidden on mobile since touch-based resizing is not practical ([ee7acaa](https://github.com/dropseed/plain/commit/ee7acaa67c))
|
|
11
|
+
- Buttons and icons are sized larger on mobile for better touch targets ([ee7acaa](https://github.com/dropseed/plain/commit/ee7acaa67c))
|
|
12
|
+
|
|
13
|
+
### Upgrade instructions
|
|
14
|
+
|
|
15
|
+
- No changes required
|
|
16
|
+
|
|
17
|
+
## [0.9.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.9.0) (2026-01-13)
|
|
18
|
+
|
|
19
|
+
### What's changed
|
|
20
|
+
|
|
21
|
+
- Added comprehensive README documentation for the package ([8f1aed3](https://github.com/dropseed/plain/commit/8f1aed34ff))
|
|
22
|
+
|
|
23
|
+
### Upgrade instructions
|
|
24
|
+
|
|
25
|
+
- No changes required
|
|
26
|
+
|
|
27
|
+
## [0.8.2](https://github.com/dropseed/plain/releases/plain-toolbar@0.8.2) (2025-12-12)
|
|
28
|
+
|
|
29
|
+
### What's changed
|
|
30
|
+
|
|
31
|
+
- Exception traceback frame badges now use more distinct colors to improve visual differentiation between app, plain, plainx, python, and third-party frames ([3911c11](https://github.com/dropseed/plain/commit/3911c1114d842aed4f48782a767c589d71f219af))
|
|
32
|
+
|
|
33
|
+
### Upgrade instructions
|
|
34
|
+
|
|
35
|
+
- No changes required
|
|
36
|
+
|
|
37
|
+
## [0.8.1](https://github.com/dropseed/plain/releases/plain-toolbar@0.8.1) (2025-12-05)
|
|
38
|
+
|
|
39
|
+
### What's changed
|
|
40
|
+
|
|
41
|
+
- Toolbar tabs now display in registration order instead of being sorted alphabetically ([ef81fb8](https://github.com/dropseed/plain/commit/ef81fb8ff0b7ab09760d4b63e904e72ee2d4b97d))
|
|
42
|
+
- Toolbar expand and close button icons are now more subtle with improved sizing ([ab038bd](https://github.com/dropseed/plain/commit/ab038bddef6b8f5108efd1c6315f3537898b20b8))
|
|
43
|
+
|
|
44
|
+
### Upgrade instructions
|
|
45
|
+
|
|
46
|
+
- No changes required
|
|
47
|
+
|
|
48
|
+
## [0.8.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.8.0) (2025-12-04)
|
|
49
|
+
|
|
50
|
+
### What's changed
|
|
51
|
+
|
|
52
|
+
- Exception toolbar now displays rich traceback frames with expandable source code context instead of raw traceback text ([9c4415e](https://github.com/dropseed/plain/commit/9c4415ed6266a36014f1fea75033f3bba4a23b7c))
|
|
53
|
+
- Frames are categorized by source (app, plain, plainx, python, third-party) with color-coded badges ([9c4415e](https://github.com/dropseed/plain/commit/9c4415ed6266a36014f1fea75033f3bba4a23b7c))
|
|
54
|
+
- App frames are expanded by default while framework/library frames are collapsed ([9c4415e](https://github.com/dropseed/plain/commit/9c4415ed6266a36014f1fea75033f3bba4a23b7c))
|
|
55
|
+
- Local variables are displayed for each frame when `DEBUG=True` ([9c4415e](https://github.com/dropseed/plain/commit/9c4415ed6266a36014f1fea75033f3bba4a23b7c))
|
|
56
|
+
- Frame filenames link directly to VS Code at the exact line number ([9c4415e](https://github.com/dropseed/plain/commit/9c4415ed6266a36014f1fea75033f3bba4a23b7c))
|
|
57
|
+
- Toggle between rich frame view and raw traceback text with the "View raw" button ([9c4415e](https://github.com/dropseed/plain/commit/9c4415ed6266a36014f1fea75033f3bba4a23b7c))
|
|
58
|
+
|
|
59
|
+
### Upgrade instructions
|
|
60
|
+
|
|
61
|
+
- No changes required
|
|
62
|
+
|
|
63
|
+
## [0.7.1](https://github.com/dropseed/plain/releases/plain-toolbar@0.7.1) (2025-10-31)
|
|
64
|
+
|
|
65
|
+
### What's changed
|
|
66
|
+
|
|
67
|
+
- The main toolbar script now includes `nonce="{{ request.csp_nonce }}"` for better Content Security Policy compliance ([10f642a](https://github.com/dropseed/plain/commit/10f642a097aa487400f2dffd341f595d93218af9))
|
|
68
|
+
|
|
69
|
+
### Upgrade instructions
|
|
70
|
+
|
|
71
|
+
- No changes required
|
|
72
|
+
|
|
73
|
+
## [0.7.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.7.0) (2025-10-29)
|
|
74
|
+
|
|
75
|
+
### What's changed
|
|
76
|
+
|
|
77
|
+
- The toolbar JavaScript now uses CSP-compliant methods by avoiding inline style injection and using CSS classes instead ([784f3dd](https://github.com/dropseed/plain/commit/784f3dd9724c11256cc3aa0a0e15c5c3eae6133c))
|
|
78
|
+
- Exception template uses `data-` attributes and event listeners instead of inline `onclick` handlers for better CSP compliance ([784f3dd](https://github.com/dropseed/plain/commit/784f3dd9724c11256cc3aa0a0e15c5c3eae6133c))
|
|
79
|
+
- Script tags now include `nonce="{{ request.csp_nonce }}"` to work with Content Security Policy ([784f3dd](https://github.com/dropseed/plain/commit/784f3dd9724c11256cc3aa0a0e15c5c3eae6133c))
|
|
80
|
+
|
|
81
|
+
### Upgrade instructions
|
|
82
|
+
|
|
83
|
+
- No changes required
|
|
84
|
+
|
|
85
|
+
## [0.6.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.6.0) (2025-10-24)
|
|
86
|
+
|
|
87
|
+
### What's changed
|
|
88
|
+
|
|
89
|
+
- Added explicit `package_label = "plaintoolbar"` to the package configuration ([d1783dd](https://github.com/dropseed/plain/commit/d1783dd564))
|
|
90
|
+
|
|
91
|
+
### Upgrade instructions
|
|
92
|
+
|
|
93
|
+
- No changes required
|
|
94
|
+
|
|
95
|
+
## [0.5.3](https://github.com/dropseed/plain/releases/plain-toolbar@0.5.3) (2025-10-22)
|
|
96
|
+
|
|
97
|
+
### What's changed
|
|
98
|
+
|
|
99
|
+
- Fixed toolbar visibility check to properly use `get_request_impersonator()` helper instead of accessing the `impersonator` attribute directly ([548a385](https://github.com/dropseed/plain/commit/548a385))
|
|
100
|
+
|
|
101
|
+
### Upgrade instructions
|
|
102
|
+
|
|
103
|
+
- No changes required
|
|
104
|
+
|
|
105
|
+
## [0.5.2](https://github.com/dropseed/plain/releases/plain-toolbar@0.5.2) (2025-10-06)
|
|
106
|
+
|
|
107
|
+
### What's changed
|
|
108
|
+
|
|
109
|
+
- Added comprehensive type annotations to improve IDE support and type checking ([c87ca27](https://github.com/dropseed/plain/commit/c87ca27ed2))
|
|
110
|
+
|
|
111
|
+
### Upgrade instructions
|
|
112
|
+
|
|
113
|
+
- No changes required
|
|
114
|
+
|
|
115
|
+
## [0.5.1](https://github.com/dropseed/plain/releases/plain-toolbar@0.5.1) (2025-10-02)
|
|
116
|
+
|
|
117
|
+
### What's changed
|
|
118
|
+
|
|
119
|
+
- The toolbar now uses `get_request_user()` helper to check user authentication, improving compatibility with different auth implementations ([2663c49](https://github.com/dropseed/plain/commit/2663c49404))
|
|
120
|
+
|
|
121
|
+
### Upgrade instructions
|
|
122
|
+
|
|
123
|
+
- No changes required
|
|
124
|
+
|
|
125
|
+
## [0.5.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.5.0) (2025-09-30)
|
|
126
|
+
|
|
127
|
+
### What's changed
|
|
128
|
+
|
|
129
|
+
- The toolbar now uses `settings.VERSION` instead of the deprecated `settings.APP_VERSION` ([4c5f216](https://github.com/dropseed/plain/commit/4c5f2166c1))
|
|
130
|
+
|
|
131
|
+
### Upgrade instructions
|
|
132
|
+
|
|
133
|
+
- If you were accessing `settings.APP_VERSION` in any toolbar customizations, update to use `settings.VERSION` instead
|
|
134
|
+
|
|
135
|
+
## [0.4.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.4.0) (2025-09-30)
|
|
136
|
+
|
|
137
|
+
### What's changed
|
|
138
|
+
|
|
139
|
+
- Renamed `ToolbarPanel` to `ToolbarItem` and `register_toolbar_panel` to `register_toolbar_item` for better clarity ([79654db](https://github.com/dropseed/plain/commit/79654dbefe))
|
|
140
|
+
- The toolbar now receives the full template context instead of just the request, allowing toolbar items to access context variables like `object` ([821bfc6](https://github.com/dropseed/plain/commit/821bfc6fab))
|
|
141
|
+
- Removed admin URL link from the request panel to reduce clutter ([5e665fd](https://github.com/dropseed/plain/commit/5e665fd4ca))
|
|
142
|
+
- Admin link and impersonation UI moved to a new AdminToolbarItem button ([821bfc6](https://github.com/dropseed/plain/commit/821bfc6fab))
|
|
143
|
+
|
|
144
|
+
### Upgrade instructions
|
|
145
|
+
|
|
146
|
+
- Replace any usage of `ToolbarPanel` with `ToolbarItem` in your custom toolbar extensions
|
|
147
|
+
- Replace any usage of `@register_toolbar_panel` decorator with `@register_toolbar_item`
|
|
148
|
+
- Update any custom toolbar items to expect `context` instead of `request` in `__init__()`: change `def __init__(self, request)` to `def __init__(self, context)` and add `self.request = context["request"]`
|
|
149
|
+
- The `panel_template_name` attribute replaces `template_name` (though `template_name` still works for backward compatibility)
|
|
150
|
+
|
|
151
|
+
## [0.3.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.3.0) (2025-09-25)
|
|
152
|
+
|
|
153
|
+
### What's changed
|
|
154
|
+
|
|
155
|
+
- Updated toolbar module autodiscovery to use the new `packages_registry.autodiscover_modules()` method ([b0b610d](https://github.com/dropseed/plain/commit/b0b610d461))
|
|
156
|
+
|
|
157
|
+
### Upgrade instructions
|
|
158
|
+
|
|
159
|
+
- No changes required
|
|
160
|
+
|
|
161
|
+
## [0.2.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.2.0) (2025-09-19)
|
|
162
|
+
|
|
163
|
+
### What's changed
|
|
164
|
+
|
|
165
|
+
- Minimum Python version raised to 3.13 ([d86e307](https://github.com/dropseed/plain/commit/d86e307efb))
|
|
166
|
+
|
|
167
|
+
### Upgrade instructions
|
|
168
|
+
|
|
169
|
+
- Upgrade your Python environment to Python 3.13 or later
|
|
170
|
+
|
|
171
|
+
## [0.1.1](https://github.com/dropseed/plain/releases/plain-toolbar@0.1.1) (2025-08-28)
|
|
172
|
+
|
|
173
|
+
### What's changed
|
|
174
|
+
|
|
175
|
+
- Improved null safety when checking user and impersonator attributes in toolbar rendering ([90568bd](https://github.com/dropseed/plain/commit/90568bdfa4))
|
|
176
|
+
|
|
177
|
+
### Upgrade instructions
|
|
178
|
+
|
|
179
|
+
- No changes required
|
|
180
|
+
|
|
181
|
+
## [0.1.0](https://github.com/dropseed/plain/releases/plain-toolbar@0.1.0) (2025-08-27)
|
|
182
|
+
|
|
183
|
+
### What's changed
|
|
184
|
+
|
|
185
|
+
- Initial release of plain-toolbar as a standalone package ([e49d54b](https://github.com/dropseed/plain/commit/e49d54bfea162424c73e54bf7ed87e93442af899))
|
|
186
|
+
- Fixed URL pattern and name display to include quotes in the request toolbar ([aa759c7](https://github.com/dropseed/plain/commit/aa759c72cae987ed8b6dd07c2e70f5fb97b6fd09))
|
|
187
|
+
|
|
188
|
+
### Upgrade instructions
|
|
189
|
+
|
|
190
|
+
- No changes required
|
|
@@ -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.
|