fastapi-lite-admin 0.1.2__tar.gz → 0.1.4__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.
- fastapi_lite_admin-0.1.4/PKG-INFO +209 -0
- fastapi_lite_admin-0.1.4/README.md +190 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/templates/dashboard.html +12 -11
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/templates/layout.html +100 -27
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/templates/model_detail.html +25 -16
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/templates/model_form.html +30 -20
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/templates/model_list.html +56 -40
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/views.py +13 -3
- fastapi_lite_admin-0.1.4/fastapi_lite_admin.egg-info/PKG-INFO +209 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/pyproject.toml +1 -1
- fastapi_lite_admin-0.1.2/PKG-INFO +0 -43
- fastapi_lite_admin-0.1.2/README.md +0 -24
- fastapi_lite_admin-0.1.2/fastapi_lite_admin.egg-info/PKG-INFO +0 -43
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/LICENSE +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/__init__.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/core/config.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/core/crud.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/core/registry.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/core/schema.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/dependencies/db.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/integrations/sqlalchemy.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/main.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/routers/admin.py +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_lite_admin.egg-info/SOURCES.txt +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_lite_admin.egg-info/dependency_links.txt +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_lite_admin.egg-info/requires.txt +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_lite_admin.egg-info/top_level.txt +0 -0
- {fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/setup.cfg +0 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastapi-lite-admin
|
|
3
|
+
Version: 0.1.4
|
|
4
|
+
Summary: A lightweight, pluggable admin panel for FastAPI
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.9
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Requires-Dist: fastapi>=0.100.0
|
|
10
|
+
Requires-Dist: sqlalchemy>=2.0.0
|
|
11
|
+
Requires-Dist: pydantic>=2.0.0
|
|
12
|
+
Requires-Dist: jinja2>=3.1.0
|
|
13
|
+
Requires-Dist: python-multipart>=0.0.6
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest; extra == "dev"
|
|
16
|
+
Requires-Dist: httpx; extra == "dev"
|
|
17
|
+
Requires-Dist: uvicorn; extra == "dev"
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# FastAPI Lite Admin
|
|
21
|
+
|
|
22
|
+
A premium, lightweight, pluggable admin panel for FastAPI and SQLAlchemy.
|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
- **Zero-config CRUD**: Automatically generate admin interfaces for your models.
|
|
27
|
+
- **ORM Agnostic**: Initial support for SQLAlchemy, designed to support others.
|
|
28
|
+
- **API First**: All admin actions are available via a clean, RESTful API.
|
|
29
|
+
- **Lightweight UI**: Fast, responsive, Jinja2 templates with server-side pagination, sorting, and search.
|
|
30
|
+
- **Attention Filters**: Highlight critical records (e.g. low stock, inactive users) requiring moderation attention.
|
|
31
|
+
- **Live Activity Badges**: "24h Activity" badges in headers and footers for real-time monitoring.
|
|
32
|
+
- **Custom System Logs**: Display a customizable activity feed on the main dashboard.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Installation
|
|
37
|
+
|
|
38
|
+
Install the package directly into your project:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pip install fastapi-lite-admin
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
For development/local setup, clone the repository and run:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install -e ".[dev]"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Quick Start & Usage
|
|
53
|
+
|
|
54
|
+
Using `FastAPI Lite Admin` is designed to be highly explicit, simple, and require minimal boilerplate. Here is how you can set it up in your application.
|
|
55
|
+
|
|
56
|
+
### 1. Initialize the Admin Panel
|
|
57
|
+
|
|
58
|
+
Instantiate the `Admin` class and mount it to your `FastAPI` instance.
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
from fastapi import FastAPI
|
|
62
|
+
from fastapi_admin_lite import Admin
|
|
63
|
+
|
|
64
|
+
app = FastAPI()
|
|
65
|
+
|
|
66
|
+
admin = Admin(
|
|
67
|
+
title="Secure Control Panel", # Dashboard title
|
|
68
|
+
base_url="/admin", # URL prefix for the admin panel
|
|
69
|
+
enable_ui=True # Enable/disable Jinja-based UI
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Mount the admin router and views to your FastAPI app
|
|
73
|
+
admin.mount(app)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This will automatically create and serve:
|
|
77
|
+
- The UI dashboard at `http://localhost:8000/admin`
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## Registering Models (Adding Tables)
|
|
82
|
+
|
|
83
|
+
To add database tables to your admin panel, register your models using `admin.register()`.
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from database import get_db # Your SQLAlchemy session dependency
|
|
87
|
+
from models import User
|
|
88
|
+
|
|
89
|
+
admin.register(
|
|
90
|
+
model=User,
|
|
91
|
+
get_db=get_db,
|
|
92
|
+
list_display=["id", "email", "is_active", "created_at"],
|
|
93
|
+
date_field="created_at",
|
|
94
|
+
attention_filter=(User.is_active == False),
|
|
95
|
+
readonly_fields=["created_at"],
|
|
96
|
+
config={"display_name": "System Users"}
|
|
97
|
+
)
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Registration Configuration Parameters
|
|
101
|
+
|
|
102
|
+
When calling `admin.register()`, you can configure how each model is represented:
|
|
103
|
+
|
|
104
|
+
| Parameter | Type | Required | Description |
|
|
105
|
+
| :--- | :--- | :--- | :--- |
|
|
106
|
+
| **`model`** | `Type[Any]` | **Yes** | The SQLAlchemy Declarative model class to generate CRUD operations for. |
|
|
107
|
+
| **`get_db`** | `Callable` | **Yes** | An async/sync generator yielding an active SQLAlchemy database session (`AsyncSession` or `Session`). |
|
|
108
|
+
| **`list_display`** | `List[str]` | No | List of field/column names to display as columns in the UI model list view. Defaults to all fields. |
|
|
109
|
+
| **`date_field`** | `str` | No | Name of the datetime field (e.g. `created_at`). Required to show the "24h Activity" count cards on the dashboard and lists. |
|
|
110
|
+
| **`attention_filter`** | `SQLAlchemy Expression` | No | A SQLAlchemy binary filter expression (e.g., `User.is_active == False` or `Product.stock < 10`) used to calculate and flag rows that require moderator attention. |
|
|
111
|
+
| **`readonly_fields`** | `List[str]` | No | List of columns that cannot be modified or set via creation or updates (e.g., auto-generated columns or timestamps like `id`, `created_at`). |
|
|
112
|
+
| **`config`** | `Dict[str, Any]` | No | Dictionary containing extra settings. Supports `"display_name"` to override the sidebar label. |
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Initialization Configurations
|
|
117
|
+
|
|
118
|
+
The `Admin` class constructor supports the following parameters for customization:
|
|
119
|
+
|
|
120
|
+
| Parameter | Type | Default | Description |
|
|
121
|
+
| :--- | :--- | :--- | :--- |
|
|
122
|
+
| **`title`** | `str` | `"FastAPI Admin Lite"` | Customized title displayed in the UI header and dashboard. |
|
|
123
|
+
| **`base_url`** | `str` | `"/admin"` | URL prefix where the admin UI is served. |
|
|
124
|
+
| **`enable_ui`** | `bool` | `True` | Whether to serve the Jinja2 templates UI. If `False`, only the API routes are registered. |
|
|
125
|
+
| **`dependencies`** | `List[Any]` | `[]` | General list of FastAPI dependencies to apply to all admin routes. |
|
|
126
|
+
| **`auth_dependency`** | `Callable` | `None` | Dependency function for custom security gating (e.g., checking tokens or cookies). |
|
|
127
|
+
| **`permission_checker`**| `Callable` | `allow all` | Custom callable to restrict user roles. |
|
|
128
|
+
| **`dashboard_models`** | `List[str]` | `None` | List of registered model names to display on the dashboard (if you want to restrict which registered models show on the home dashboard). |
|
|
129
|
+
| **`get_logs`** | `Callable` | `None` | An optional callable (async or sync) returning system logs to display on the dashboard activity log feed. |
|
|
130
|
+
| **`logs_config`** | `Dict[str, Any]` | `{"title": "System Activity", "columns": ["level", "timestamp", "message"]}` | Config dictionary to customize dashboard log columns and activity title. |
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Gating Access & Security
|
|
135
|
+
|
|
136
|
+
By default, the admin panel warns if no authentication is configured. You can gate the admin panel and its APIs using standard FastAPI dependencies:
|
|
137
|
+
|
|
138
|
+
### 1. `auth_dependency`
|
|
139
|
+
|
|
140
|
+
Pass a dependency to `Admin` constructor that handles authentication.
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from fastapi import Header, HTTPException
|
|
144
|
+
|
|
145
|
+
async def verify_admin_token(x_admin_token: str = Header(None)):
|
|
146
|
+
if x_admin_token != "super-secret-admin-token":
|
|
147
|
+
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
148
|
+
return x_admin_token
|
|
149
|
+
|
|
150
|
+
admin = Admin(
|
|
151
|
+
title="Secure Admin",
|
|
152
|
+
auth_dependency=verify_admin_token
|
|
153
|
+
)
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### 2. `permission_checker`
|
|
157
|
+
|
|
158
|
+
Restrict granular user roles with a custom callable:
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
async def check_permissions(user: Any = Depends(get_current_user)) -> bool:
|
|
162
|
+
return user.is_superuser
|
|
163
|
+
|
|
164
|
+
admin = Admin(
|
|
165
|
+
title="Staff Portal",
|
|
166
|
+
permission_checker=check_permissions
|
|
167
|
+
)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Custom Dashboard Activity Logs
|
|
173
|
+
|
|
174
|
+
Configure a live activity log feed on the dashboard homepage:
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
async def fetch_system_logs():
|
|
178
|
+
# Fetch logs from a database table, file, or third-party service
|
|
179
|
+
return [
|
|
180
|
+
{"level": "info", "timestamp": "10:45 AM", "event": "User signup", "user": "alice@example.com"},
|
|
181
|
+
{"level": "error", "timestamp": "11:20 AM", "event": "Payment failed", "user": "bob@example.com"}
|
|
182
|
+
]
|
|
183
|
+
|
|
184
|
+
admin = Admin(
|
|
185
|
+
title="Command Center",
|
|
186
|
+
get_logs=fetch_system_logs,
|
|
187
|
+
logs_config={
|
|
188
|
+
"title": "Recent Activity Feed",
|
|
189
|
+
"columns": ["level", "timestamp", "event", "user"]
|
|
190
|
+
}
|
|
191
|
+
)
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Running the Example Application
|
|
197
|
+
|
|
198
|
+
We package a complete working example inside the `/example` directory. To run it:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# 1. Install dependencies with dev options
|
|
202
|
+
pip install -e ".[dev]"
|
|
203
|
+
|
|
204
|
+
# 2. Run the example application
|
|
205
|
+
python -m example.main
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Then visit `http://localhost:8001/admin` in your web browser. You'll be able to view logs, add/update users, search database entries, and filter elements dynamically.
|
|
209
|
+
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# FastAPI Lite Admin
|
|
2
|
+
|
|
3
|
+
A premium, lightweight, pluggable admin panel for FastAPI and SQLAlchemy.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Zero-config CRUD**: Automatically generate admin interfaces for your models.
|
|
8
|
+
- **ORM Agnostic**: Initial support for SQLAlchemy, designed to support others.
|
|
9
|
+
- **API First**: All admin actions are available via a clean, RESTful API.
|
|
10
|
+
- **Lightweight UI**: Fast, responsive, Jinja2 templates with server-side pagination, sorting, and search.
|
|
11
|
+
- **Attention Filters**: Highlight critical records (e.g. low stock, inactive users) requiring moderation attention.
|
|
12
|
+
- **Live Activity Badges**: "24h Activity" badges in headers and footers for real-time monitoring.
|
|
13
|
+
- **Custom System Logs**: Display a customizable activity feed on the main dashboard.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
Install the package directly into your project:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install fastapi-lite-admin
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
For development/local setup, clone the repository and run:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install -e ".[dev]"
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick Start & Usage
|
|
34
|
+
|
|
35
|
+
Using `FastAPI Lite Admin` is designed to be highly explicit, simple, and require minimal boilerplate. Here is how you can set it up in your application.
|
|
36
|
+
|
|
37
|
+
### 1. Initialize the Admin Panel
|
|
38
|
+
|
|
39
|
+
Instantiate the `Admin` class and mount it to your `FastAPI` instance.
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from fastapi import FastAPI
|
|
43
|
+
from fastapi_admin_lite import Admin
|
|
44
|
+
|
|
45
|
+
app = FastAPI()
|
|
46
|
+
|
|
47
|
+
admin = Admin(
|
|
48
|
+
title="Secure Control Panel", # Dashboard title
|
|
49
|
+
base_url="/admin", # URL prefix for the admin panel
|
|
50
|
+
enable_ui=True # Enable/disable Jinja-based UI
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
# Mount the admin router and views to your FastAPI app
|
|
54
|
+
admin.mount(app)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This will automatically create and serve:
|
|
58
|
+
- The UI dashboard at `http://localhost:8000/admin`
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
## Registering Models (Adding Tables)
|
|
63
|
+
|
|
64
|
+
To add database tables to your admin panel, register your models using `admin.register()`.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from database import get_db # Your SQLAlchemy session dependency
|
|
68
|
+
from models import User
|
|
69
|
+
|
|
70
|
+
admin.register(
|
|
71
|
+
model=User,
|
|
72
|
+
get_db=get_db,
|
|
73
|
+
list_display=["id", "email", "is_active", "created_at"],
|
|
74
|
+
date_field="created_at",
|
|
75
|
+
attention_filter=(User.is_active == False),
|
|
76
|
+
readonly_fields=["created_at"],
|
|
77
|
+
config={"display_name": "System Users"}
|
|
78
|
+
)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Registration Configuration Parameters
|
|
82
|
+
|
|
83
|
+
When calling `admin.register()`, you can configure how each model is represented:
|
|
84
|
+
|
|
85
|
+
| Parameter | Type | Required | Description |
|
|
86
|
+
| :--- | :--- | :--- | :--- |
|
|
87
|
+
| **`model`** | `Type[Any]` | **Yes** | The SQLAlchemy Declarative model class to generate CRUD operations for. |
|
|
88
|
+
| **`get_db`** | `Callable` | **Yes** | An async/sync generator yielding an active SQLAlchemy database session (`AsyncSession` or `Session`). |
|
|
89
|
+
| **`list_display`** | `List[str]` | No | List of field/column names to display as columns in the UI model list view. Defaults to all fields. |
|
|
90
|
+
| **`date_field`** | `str` | No | Name of the datetime field (e.g. `created_at`). Required to show the "24h Activity" count cards on the dashboard and lists. |
|
|
91
|
+
| **`attention_filter`** | `SQLAlchemy Expression` | No | A SQLAlchemy binary filter expression (e.g., `User.is_active == False` or `Product.stock < 10`) used to calculate and flag rows that require moderator attention. |
|
|
92
|
+
| **`readonly_fields`** | `List[str]` | No | List of columns that cannot be modified or set via creation or updates (e.g., auto-generated columns or timestamps like `id`, `created_at`). |
|
|
93
|
+
| **`config`** | `Dict[str, Any]` | No | Dictionary containing extra settings. Supports `"display_name"` to override the sidebar label. |
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Initialization Configurations
|
|
98
|
+
|
|
99
|
+
The `Admin` class constructor supports the following parameters for customization:
|
|
100
|
+
|
|
101
|
+
| Parameter | Type | Default | Description |
|
|
102
|
+
| :--- | :--- | :--- | :--- |
|
|
103
|
+
| **`title`** | `str` | `"FastAPI Admin Lite"` | Customized title displayed in the UI header and dashboard. |
|
|
104
|
+
| **`base_url`** | `str` | `"/admin"` | URL prefix where the admin UI is served. |
|
|
105
|
+
| **`enable_ui`** | `bool` | `True` | Whether to serve the Jinja2 templates UI. If `False`, only the API routes are registered. |
|
|
106
|
+
| **`dependencies`** | `List[Any]` | `[]` | General list of FastAPI dependencies to apply to all admin routes. |
|
|
107
|
+
| **`auth_dependency`** | `Callable` | `None` | Dependency function for custom security gating (e.g., checking tokens or cookies). |
|
|
108
|
+
| **`permission_checker`**| `Callable` | `allow all` | Custom callable to restrict user roles. |
|
|
109
|
+
| **`dashboard_models`** | `List[str]` | `None` | List of registered model names to display on the dashboard (if you want to restrict which registered models show on the home dashboard). |
|
|
110
|
+
| **`get_logs`** | `Callable` | `None` | An optional callable (async or sync) returning system logs to display on the dashboard activity log feed. |
|
|
111
|
+
| **`logs_config`** | `Dict[str, Any]` | `{"title": "System Activity", "columns": ["level", "timestamp", "message"]}` | Config dictionary to customize dashboard log columns and activity title. |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Gating Access & Security
|
|
116
|
+
|
|
117
|
+
By default, the admin panel warns if no authentication is configured. You can gate the admin panel and its APIs using standard FastAPI dependencies:
|
|
118
|
+
|
|
119
|
+
### 1. `auth_dependency`
|
|
120
|
+
|
|
121
|
+
Pass a dependency to `Admin` constructor that handles authentication.
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from fastapi import Header, HTTPException
|
|
125
|
+
|
|
126
|
+
async def verify_admin_token(x_admin_token: str = Header(None)):
|
|
127
|
+
if x_admin_token != "super-secret-admin-token":
|
|
128
|
+
raise HTTPException(status_code=401, detail="Unauthorized")
|
|
129
|
+
return x_admin_token
|
|
130
|
+
|
|
131
|
+
admin = Admin(
|
|
132
|
+
title="Secure Admin",
|
|
133
|
+
auth_dependency=verify_admin_token
|
|
134
|
+
)
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 2. `permission_checker`
|
|
138
|
+
|
|
139
|
+
Restrict granular user roles with a custom callable:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
async def check_permissions(user: Any = Depends(get_current_user)) -> bool:
|
|
143
|
+
return user.is_superuser
|
|
144
|
+
|
|
145
|
+
admin = Admin(
|
|
146
|
+
title="Staff Portal",
|
|
147
|
+
permission_checker=check_permissions
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Custom Dashboard Activity Logs
|
|
154
|
+
|
|
155
|
+
Configure a live activity log feed on the dashboard homepage:
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
async def fetch_system_logs():
|
|
159
|
+
# Fetch logs from a database table, file, or third-party service
|
|
160
|
+
return [
|
|
161
|
+
{"level": "info", "timestamp": "10:45 AM", "event": "User signup", "user": "alice@example.com"},
|
|
162
|
+
{"level": "error", "timestamp": "11:20 AM", "event": "Payment failed", "user": "bob@example.com"}
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
admin = Admin(
|
|
166
|
+
title="Command Center",
|
|
167
|
+
get_logs=fetch_system_logs,
|
|
168
|
+
logs_config={
|
|
169
|
+
"title": "Recent Activity Feed",
|
|
170
|
+
"columns": ["level", "timestamp", "event", "user"]
|
|
171
|
+
}
|
|
172
|
+
)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Running the Example Application
|
|
178
|
+
|
|
179
|
+
We package a complete working example inside the `/example` directory. To run it:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# 1. Install dependencies with dev options
|
|
183
|
+
pip install -e ".[dev]"
|
|
184
|
+
|
|
185
|
+
# 2. Run the example application
|
|
186
|
+
python -m example.main
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Then visit `http://localhost:8001/admin` in your web browser. You'll be able to view logs, add/update users, search database entries, and filter elements dynamically.
|
|
190
|
+
|
{fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/templates/dashboard.html
RENAMED
|
@@ -90,26 +90,27 @@
|
|
|
90
90
|
}
|
|
91
91
|
|
|
92
92
|
.badge {
|
|
93
|
-
padding: 4px
|
|
94
|
-
border-radius:
|
|
93
|
+
padding: 4px 10px;
|
|
94
|
+
border-radius: 12px;
|
|
95
95
|
font-size: 0.7rem;
|
|
96
96
|
font-weight: 700;
|
|
97
97
|
text-transform: uppercase;
|
|
98
|
+
letter-spacing: 0.025em;
|
|
98
99
|
}
|
|
99
100
|
|
|
100
|
-
.badge-info { background-color:
|
|
101
|
-
.badge-warn { background-color:
|
|
102
|
-
.badge-error { background-color:
|
|
103
|
-
.badge-success { background-color:
|
|
101
|
+
.badge-info { background-color: var(--info-bg); color: var(--info-text); }
|
|
102
|
+
.badge-warn { background-color: var(--warning-bg); color: var(--warning-text); }
|
|
103
|
+
.badge-error { background-color: var(--error-bg); color: var(--error-text); }
|
|
104
|
+
.badge-success { background-color: var(--success-bg); color: var(--success-text); }
|
|
104
105
|
|
|
105
106
|
.status-text {
|
|
106
107
|
font-weight: 600;
|
|
107
108
|
font-family: monospace;
|
|
108
109
|
}
|
|
109
110
|
|
|
110
|
-
.status-200 { color: var(--success); }
|
|
111
|
-
.status-422 { color: var(--error); }
|
|
112
|
-
.status-latency { color: var(--warning); }
|
|
111
|
+
.status-200 { color: var(--success-text); }
|
|
112
|
+
.status-422 { color: var(--error-text); }
|
|
113
|
+
.status-latency { color: var(--warning-text); }
|
|
113
114
|
|
|
114
115
|
/* Quick Actions */
|
|
115
116
|
.quick-actions {
|
|
@@ -134,12 +135,12 @@
|
|
|
134
135
|
.action-icon {
|
|
135
136
|
width: 48px;
|
|
136
137
|
height: 48px;
|
|
137
|
-
background-color:
|
|
138
|
+
background-color: var(--bg-surface);
|
|
138
139
|
border-radius: 12px;
|
|
139
140
|
display: flex;
|
|
140
141
|
align-items: center;
|
|
141
142
|
justify-content: center;
|
|
142
|
-
color: var(--
|
|
143
|
+
color: var(--primary);
|
|
143
144
|
font-size: 1.25rem;
|
|
144
145
|
}
|
|
145
146
|
|
{fastapi_lite_admin-0.1.2 → fastapi_lite_admin-0.1.4}/fastapi_admin_lite/ui/templates/layout.html
RENAMED
|
@@ -8,28 +8,68 @@
|
|
|
8
8
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
9
9
|
<style>
|
|
10
10
|
:root {
|
|
11
|
-
--primary: #
|
|
12
|
-
--primary-hover: #
|
|
11
|
+
--primary: #6366f1;
|
|
12
|
+
--primary-hover: #4f46e5;
|
|
13
13
|
--bg-main: #f8fafc;
|
|
14
|
-
--bg-
|
|
14
|
+
--bg-card: #ffffff;
|
|
15
|
+
--bg-surface: #f1f5f9;
|
|
16
|
+
--bg-header: #f8fafc;
|
|
17
|
+
--bg-sidebar: #0f172a;
|
|
15
18
|
--text-main: #1e293b;
|
|
16
19
|
--text-muted: #64748b;
|
|
20
|
+
--sidebar-text: #94a3b8;
|
|
21
|
+
--sidebar-text-active: #ffffff;
|
|
17
22
|
--border: #e2e8f0;
|
|
18
|
-
--
|
|
19
|
-
--
|
|
20
|
-
--
|
|
21
|
-
--
|
|
22
|
-
--
|
|
23
|
+
--sidebar-hover: #1e293b;
|
|
24
|
+
--sidebar-active: #334155;
|
|
25
|
+
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
26
|
+
--sidebar-width: 240px;
|
|
27
|
+
--topbar-height: 48px;
|
|
28
|
+
|
|
29
|
+
/* Status Colors */
|
|
30
|
+
--success-bg: #dcfce7;
|
|
31
|
+
--success-text: #166534;
|
|
32
|
+
--warning-bg: #fef9c3;
|
|
33
|
+
--warning-text: #854d0e;
|
|
34
|
+
--error-bg: #fee2e2;
|
|
35
|
+
--error-text: #991b1b;
|
|
36
|
+
--info-bg: #e0f2fe;
|
|
37
|
+
--info-text: #075985;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
[data-theme="dark"] {
|
|
41
|
+
--bg-main: #020617;
|
|
42
|
+
--bg-card: #0f172a;
|
|
43
|
+
--bg-surface: #1e293b;
|
|
44
|
+
--bg-header: #1e293b;
|
|
45
|
+
--bg-sidebar: #020617;
|
|
46
|
+
--text-main: #f1f5f9;
|
|
47
|
+
--text-muted: #94a3b8;
|
|
48
|
+
--border: #1e293b;
|
|
49
|
+
--sidebar-hover: #0f172a;
|
|
50
|
+
--sidebar-active: #1e293b;
|
|
51
|
+
--shadow: 0 4px 6px -1px rgb(0 0 0 / 0.3);
|
|
52
|
+
|
|
53
|
+
/* Status Colors - Dark Mode */
|
|
54
|
+
--success-bg: rgba(22, 101, 52, 0.2);
|
|
55
|
+
--success-text: #4ade80;
|
|
56
|
+
--warning-bg: rgba(133, 77, 14, 0.2);
|
|
57
|
+
--warning-text: #facc15;
|
|
58
|
+
--error-bg: rgba(153, 27, 27, 0.2);
|
|
59
|
+
--error-text: #f87171;
|
|
60
|
+
--info-bg: rgba(7, 89, 133, 0.2);
|
|
61
|
+
--info-text: #38bdf8;
|
|
23
62
|
}
|
|
24
63
|
|
|
25
64
|
* {
|
|
26
65
|
margin: 0;
|
|
27
66
|
padding: 0;
|
|
28
67
|
box-sizing: border-box;
|
|
68
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
69
|
+
transition: background-color 0.2s, border-color 0.2s, color 0.2s;
|
|
29
70
|
}
|
|
30
71
|
|
|
31
72
|
body {
|
|
32
|
-
font-family: 'Inter', sans-serif;
|
|
33
73
|
background-color: var(--bg-main);
|
|
34
74
|
color: var(--text-main);
|
|
35
75
|
display: flex;
|
|
@@ -69,14 +109,14 @@
|
|
|
69
109
|
.logo-text {
|
|
70
110
|
font-weight: 700;
|
|
71
111
|
font-size: 1.1rem;
|
|
72
|
-
color: var(--text-
|
|
112
|
+
color: var(--sidebar-text-active);
|
|
73
113
|
}
|
|
74
114
|
|
|
75
115
|
.logo-subtext {
|
|
76
116
|
font-size: 0.7rem;
|
|
77
117
|
text-transform: uppercase;
|
|
78
118
|
letter-spacing: 0.05em;
|
|
79
|
-
color: var(--text
|
|
119
|
+
color: var(--sidebar-text);
|
|
80
120
|
margin-top: -2px;
|
|
81
121
|
}
|
|
82
122
|
|
|
@@ -91,7 +131,7 @@
|
|
|
91
131
|
gap: 12px;
|
|
92
132
|
padding: 12px 16px;
|
|
93
133
|
text-decoration: none;
|
|
94
|
-
color: var(--text
|
|
134
|
+
color: var(--sidebar-text);
|
|
95
135
|
border-radius: 8px;
|
|
96
136
|
font-weight: 500;
|
|
97
137
|
transition: all 0.2s;
|
|
@@ -99,13 +139,13 @@
|
|
|
99
139
|
}
|
|
100
140
|
|
|
101
141
|
.nav-item:hover {
|
|
102
|
-
background-color:
|
|
103
|
-
color: var(--text-
|
|
142
|
+
background-color: var(--sidebar-hover);
|
|
143
|
+
color: var(--sidebar-text-active);
|
|
104
144
|
}
|
|
105
145
|
|
|
106
146
|
.nav-item.active {
|
|
107
|
-
background-color:
|
|
108
|
-
color: var(--
|
|
147
|
+
background-color: var(--sidebar-active);
|
|
148
|
+
color: var(--sidebar-text-active);
|
|
109
149
|
}
|
|
110
150
|
|
|
111
151
|
.sidebar-footer {
|
|
@@ -134,11 +174,12 @@
|
|
|
134
174
|
.user-info .name {
|
|
135
175
|
font-size: 0.9rem;
|
|
136
176
|
font-weight: 600;
|
|
177
|
+
color: var(--sidebar-text-active);
|
|
137
178
|
}
|
|
138
179
|
|
|
139
180
|
.user-info .email {
|
|
140
181
|
font-size: 0.75rem;
|
|
141
|
-
color: var(--text
|
|
182
|
+
color: var(--sidebar-text);
|
|
142
183
|
}
|
|
143
184
|
|
|
144
185
|
/* Main Content */
|
|
@@ -151,8 +192,8 @@
|
|
|
151
192
|
|
|
152
193
|
/* Topbar */
|
|
153
194
|
.topbar {
|
|
154
|
-
height:
|
|
155
|
-
background-color: var(--
|
|
195
|
+
height: var(--topbar-height);
|
|
196
|
+
background-color: var(--bg-card);
|
|
156
197
|
border-bottom: 1px solid var(--border);
|
|
157
198
|
display: flex;
|
|
158
199
|
align-items: center;
|
|
@@ -167,13 +208,14 @@
|
|
|
167
208
|
|
|
168
209
|
.search-box input {
|
|
169
210
|
width: 100%;
|
|
170
|
-
padding:
|
|
171
|
-
background-color:
|
|
172
|
-
border: 1px solid
|
|
173
|
-
border-radius:
|
|
211
|
+
padding: 8px 12px 8px 36px;
|
|
212
|
+
background-color: var(--bg-surface);
|
|
213
|
+
border: 1px solid var(--border);
|
|
214
|
+
border-radius: 8px;
|
|
174
215
|
outline: none;
|
|
175
216
|
font-size: 0.85rem;
|
|
176
217
|
transition: all 0.2s;
|
|
218
|
+
color: var(--text-main);
|
|
177
219
|
}
|
|
178
220
|
|
|
179
221
|
.search-box i {
|
|
@@ -217,11 +259,11 @@
|
|
|
217
259
|
|
|
218
260
|
/* Shared Components */
|
|
219
261
|
.card {
|
|
220
|
-
background-color: var(--
|
|
262
|
+
background-color: var(--bg-card);
|
|
221
263
|
border: 1px solid var(--border);
|
|
222
264
|
border-radius: 12px;
|
|
223
265
|
padding: 24px;
|
|
224
|
-
box-shadow:
|
|
266
|
+
box-shadow: var(--shadow);
|
|
225
267
|
}
|
|
226
268
|
|
|
227
269
|
.btn {
|
|
@@ -244,16 +286,17 @@
|
|
|
244
286
|
|
|
245
287
|
.btn-primary:hover {
|
|
246
288
|
background-color: var(--primary-hover);
|
|
289
|
+
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.2);
|
|
247
290
|
}
|
|
248
291
|
|
|
249
292
|
.btn-secondary {
|
|
250
|
-
background-color:
|
|
293
|
+
background-color: var(--bg-card);
|
|
251
294
|
border-color: var(--border);
|
|
252
295
|
color: var(--text-main);
|
|
253
296
|
}
|
|
254
297
|
|
|
255
298
|
.btn-secondary:hover {
|
|
256
|
-
background-color:
|
|
299
|
+
background-color: var(--bg-surface);
|
|
257
300
|
}
|
|
258
301
|
|
|
259
302
|
/* Extra CSS from child templates */
|
|
@@ -311,6 +354,9 @@
|
|
|
311
354
|
<input type="text" placeholder="Search resources...">
|
|
312
355
|
</div>
|
|
313
356
|
<div class="topbar-actions">
|
|
357
|
+
<button id="theme-toggle" class="btn-icon" style="background: none; border: none; cursor: pointer; color: var(--text-muted);">
|
|
358
|
+
<i class="fas fa-moon"></i>
|
|
359
|
+
</button>
|
|
314
360
|
<i class="far fa-bell"></i>
|
|
315
361
|
<i class="far fa-question-circle"></i>
|
|
316
362
|
<div class="avatar" style="width: 32px; height: 32px;">
|
|
@@ -324,6 +370,33 @@
|
|
|
324
370
|
</div>
|
|
325
371
|
</div>
|
|
326
372
|
|
|
373
|
+
<script>
|
|
374
|
+
// Theme Toggle Logic
|
|
375
|
+
const themeToggle = document.getElementById('theme-toggle');
|
|
376
|
+
const icon = themeToggle.querySelector('i');
|
|
377
|
+
|
|
378
|
+
// Check for saved theme or default to light
|
|
379
|
+
const savedTheme = localStorage.getItem('theme') || 'light';
|
|
380
|
+
document.documentElement.setAttribute('data-theme', savedTheme);
|
|
381
|
+
updateIcon(savedTheme);
|
|
382
|
+
|
|
383
|
+
themeToggle.addEventListener('click', () => {
|
|
384
|
+
const currentTheme = document.documentElement.getAttribute('data-theme');
|
|
385
|
+
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
|
386
|
+
|
|
387
|
+
document.documentElement.setAttribute('data-theme', newTheme);
|
|
388
|
+
localStorage.setItem('theme', newTheme);
|
|
389
|
+
updateIcon(newTheme);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
function updateIcon(theme) {
|
|
393
|
+
if (theme === 'dark') {
|
|
394
|
+
icon.className = 'fas fa-sun';
|
|
395
|
+
} else {
|
|
396
|
+
icon.className = 'fas fa-moon';
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
</script>
|
|
327
400
|
{% block extra_js %}{% endblock %}
|
|
328
401
|
</body>
|
|
329
402
|
</html>
|