Custom Views and Embeds¶
Beyond model-based views, litestar-admin provides several specialized view types for building rich admin interfaces. This guide covers all non-model view types and when to use them.
View Type Overview¶
litestar-admin supports six view types, each designed for specific use cases:
View Type |
Use Case |
Has API Routes |
|---|---|---|
|
CRUD operations on SQLAlchemy models |
Yes |
|
Data from non-model sources (APIs, files, memory) |
Yes |
|
One-off admin operations with forms |
Yes |
|
Static or dynamic content pages |
Yes |
|
External navigation links |
No |
|
Embedded iframes or React components |
Yes |
BaseAdminView¶
All view types inherit from BaseAdminView, which provides common functionality for navigation, access control, and identification.
Common Attributes¶
from litestar_admin.views import BaseAdminView
class MyView(BaseAdminView):
# Display name in sidebar
name = "My View"
# Plural display name (auto-generated if not set)
name_plural = "My Views"
# URL-safe identifier (auto-generated from name)
identity = "my-view"
# Icon name for sidebar (FontAwesome)
icon = "file"
# Category for sidebar grouping
category = "Tools"
# Sort order within category (lower = higher)
order = 0
# Whether to show in navigation
is_visible = True
# Default access control
can_access = True
# Permission/role requirements
required_permission = "admin.view"
required_role = "admin"
Access Control¶
Override is_accessible for dynamic access control:
from litestar.connection import ASGIConnection
class SecureView(BaseAdminView):
@classmethod
async def is_accessible(cls, connection: ASGIConnection) -> bool:
user = getattr(connection, "user", None)
return user is not None and user.is_admin
CustomView¶
CustomView enables admin interfaces for data that doesn’t come from SQLAlchemy models. Use it for external APIs, files, in-memory data, or any custom data source.
Column Definitions¶
Unlike model views that introspect the database schema, custom views require explicit column definitions:
from litestar_admin.views import CustomView, ColumnDefinition, ListResult
class ExternalUsersView(CustomView):
name = "External Users"
icon = "users"
pk_field = "id"
columns = [
ColumnDefinition(
name="id",
label="ID",
type="integer",
sortable=True,
),
ColumnDefinition(
name="email",
label="Email Address",
type="email",
searchable=True,
),
ColumnDefinition(
name="name",
label="Full Name",
type="string",
sortable=True,
searchable=True,
),
ColumnDefinition(
name="created_at",
label="Created",
type="datetime",
sortable=True,
),
ColumnDefinition(
name="is_active",
label="Active",
type="boolean",
filterable=True,
),
]
ColumnDefinition Options¶
Attribute |
Type |
Default |
Description |
|---|---|---|---|
|
|
Required |
Internal field name |
|
|
Auto from name |
Display label |
|
|
|
Data type (see below) |
|
|
|
Enable sorting |
|
|
|
Include in search |
|
|
|
Enable filtering |
|
|
|
Show in list view |
|
|
|
Display format |
|
|
|
Custom render template |
Supported Column Types¶
string- Plain texttext- Long textinteger- Whole numbersfloat- Decimal numbersboolean- True/falsedatetime- Date and timedate- Date onlytime- Time onlyemail- Email addressurl- Web URLuuid- UUID stringjson- JSON object
Data Provider Methods¶
Custom views must implement at least get_list and get_one:
from typing import Any, Literal
class MyCustomView(CustomView):
# ... column definitions ...
async def get_list(
self,
page: int = 1,
page_size: int = 25,
filters: dict[str, Any] | None = None,
sort_by: str | None = None,
sort_order: Literal["asc", "desc"] = "asc",
search: str | None = None,
) -> ListResult:
"""Fetch paginated list of items."""
# Implement your data fetching logic
items = await fetch_from_source()
return ListResult(
items=items,
total=len(items),
page=page,
page_size=page_size,
)
async def get_one(self, item_id: str) -> dict[str, Any] | None:
"""Fetch a single item by ID."""
# Implement your single-item fetch
return await fetch_item(item_id)
Optional CRUD Methods¶
Enable create, update, and delete by implementing these methods and setting the corresponding flags:
class EditableCustomView(CustomView):
can_create = True
can_edit = True
can_delete = True
async def create(self, data: dict[str, Any]) -> dict[str, Any]:
"""Create a new item."""
# Validate and create
return created_item
async def update(self, item_id: str, data: dict[str, Any]) -> dict[str, Any]:
"""Update an existing item."""
# Validate and update
return updated_item
async def delete(self, item_id: str) -> bool:
"""Delete an item."""
# Perform deletion
return True
Lifecycle Hooks¶
Custom views support hooks for preprocessing and side effects:
class HookedCustomView(CustomView):
async def on_before_create(self, data: dict[str, Any]) -> dict[str, Any]:
"""Modify data before creating."""
data["created_at"] = datetime.utcnow().isoformat()
return data
async def on_after_create(self, item: dict[str, Any]) -> None:
"""Side effects after creating."""
await send_notification(f"Created: {item['id']}")
async def on_before_update(
self,
item_id: str,
data: dict[str, Any],
) -> dict[str, Any]:
"""Modify data before updating."""
data["updated_at"] = datetime.utcnow().isoformat()
return data
async def on_after_update(self, item: dict[str, Any]) -> None:
"""Side effects after updating."""
await invalidate_cache(item["id"])
async def on_before_delete(self, item_id: str) -> None:
"""Actions before deleting."""
await backup_item(item_id)
async def on_after_delete(self, item_id: str) -> None:
"""Cleanup after deleting."""
await remove_from_search_index(item_id)
Built-in Data Providers¶
litestar-admin includes three pre-built CustomView implementations for common data sources.
InMemoryView¶
Stores data in memory. Useful for settings, caches, or testing.
from litestar_admin.contrib.providers import InMemoryView
from litestar_admin.views import ColumnDefinition
class AppSettingsView(InMemoryView):
name = "App Settings"
icon = "cog"
pk_field = "key"
can_create = True
can_edit = True
can_delete = True
columns = [
ColumnDefinition(name="key", type="string", sortable=True),
ColumnDefinition(name="value", type="string"),
ColumnDefinition(name="description", type="text"),
]
# Pre-populate with default settings
_data = {
"site_name": {
"key": "site_name",
"value": "My Application",
"description": "Displayed in the header",
},
"maintenance_mode": {
"key": "maintenance_mode",
"value": "false",
"description": "Enable maintenance mode",
},
}
InMemoryView Features¶
Auto-generate primary keys: Set
auto_generate_pk = Trueto auto-generate UUIDsSeed data: Use
seed_data()class method to populate initial dataClear data: Use
clear_data()class method to reset the store
# Seed data at startup
AppSettingsView.seed_data([
{"key": "theme", "value": "dark"},
{"key": "language", "value": "en"},
])
# Clear all data
AppSettingsView.clear_data()
Warning
Data in InMemoryView is lost when the application restarts. Use JSONFileView or a database for persistence.
JSONFileView¶
Stores data in a JSON file for simple persistence.
from litestar_admin.contrib.providers import JSONFileView
from litestar_admin.views import ColumnDefinition
class BookmarksView(JSONFileView):
name = "Bookmarks"
icon = "bookmark"
file_path = "/data/bookmarks.json" # Required
can_create = True
can_edit = True
can_delete = True
columns = [
ColumnDefinition(name="id", type="uuid"),
ColumnDefinition(name="title", type="string", sortable=True, searchable=True),
ColumnDefinition(name="url", type="url"),
ColumnDefinition(name="tags", type="json"),
ColumnDefinition(name="created_at", type="datetime"),
]
# Optional configuration
auto_generate_pk = True # Auto-generate UUID for new items
create_file_if_missing = True # Create file if it doesn't exist
indent = 2 # JSON indentation (None for compact)
JSONFileView Options¶
Attribute |
Default |
Description |
|---|---|---|
|
Required |
Path to JSON file |
|
|
Auto-generate UUIDs for new items |
|
|
Create file if it doesn’t exist |
|
|
JSON indentation |
Note
JSONFileView uses synchronous file I/O. For high-concurrency scenarios, consider using a proper database or implementing async file operations with aiofiles.
HTTPAPIView¶
Fetches data from external REST APIs.
from litestar_admin.contrib.providers import HTTPAPIView
from litestar_admin.views import ColumnDefinition
class GitHubReposView(HTTPAPIView):
name = "GitHub Repositories"
icon = "github"
# API configuration
api_base_url = "https://api.github.com"
api_headers = {"Accept": "application/vnd.github.v3+json"}
api_timeout = 30.0
# Endpoint paths
list_endpoint = "/users/octocat/repos"
detail_endpoint = "/repos/octocat/{id}"
# Response parsing
items_key = None # Response is a list directly
total_key = None # Use len(items) for total
# Request parameter names
page_param = "page"
page_size_param = "per_page"
columns = [
ColumnDefinition(name="id", type="integer"),
ColumnDefinition(name="name", type="string", sortable=True),
ColumnDefinition(name="full_name", type="string"),
ColumnDefinition(name="description", type="text", searchable=True),
ColumnDefinition(name="stargazers_count", type="integer", sortable=True),
ColumnDefinition(name="html_url", type="url"),
]
HTTPAPIView Options¶
Attribute |
Default |
Description |
|---|---|---|
|
Required |
Base URL for API |
|
|
Default request headers |
|
|
Request timeout (seconds) |
|
|
Endpoint for listing |
|
|
Endpoint for single item |
|
|
Endpoint for creating |
|
|
Endpoint for updating |
|
|
Endpoint for deleting |
|
|
Response key for items list |
|
|
Response key for total count |
|
|
Query param for page |
|
|
Query param for page size |
|
|
Query param for search |
|
|
Query param for sort field |
|
|
Query param for sort order |
Custom Request Handling¶
Override methods for custom API interactions:
class CustomAPIView(HTTPAPIView):
username = "octocat" # Custom parameter
async def get_list(self, **kwargs) -> ListResult:
# Build custom endpoint
endpoint = f"/users/{self.username}/repos"
return await self._fetch_list(endpoint, **kwargs)
async def get_one(self, item_id: str) -> dict[str, Any] | None:
endpoint = f"/repos/{self.username}/{item_id}"
return await self._fetch_one(endpoint)
Note
HTTPAPIView requires the httpx package. Install with: pip install httpx
ActionView¶
ActionView creates standalone admin actions with optional form inputs. Use it for one-off operations like cache clearing, data imports, or maintenance tasks.
Basic Action¶
from litestar_admin.views import ActionView, ActionResult
class ClearCacheAction(ActionView):
name = "Clear Cache"
icon = "trash"
category = "Maintenance"
confirmation_message = "Are you sure you want to clear the cache?"
async def execute(self, data: dict[str, Any]) -> ActionResult:
await cache_service.clear_all()
return ActionResult(
success=True,
message="Cache cleared successfully!",
)
Form Fields¶
Add input fields to collect data before execution:
from litestar_admin.views import ActionView, ActionResult, FormField
class SendNewsletterAction(ActionView):
name = "Send Newsletter"
icon = "envelope"
category = "Marketing"
submit_label = "Send Now"
dangerous = True # Shows warning styling
form_fields = [
FormField(
name="subject",
label="Email Subject",
field_type="text",
required=True,
placeholder="Enter subject line...",
),
FormField(
name="template",
label="Template",
field_type="select",
required=True,
options=[
{"value": "weekly", "label": "Weekly Digest"},
{"value": "promo", "label": "Promotional"},
{"value": "announcement", "label": "Announcement"},
],
),
FormField(
name="audience",
label="Target Audience",
field_type="multiselect",
options=[
{"value": "all", "label": "All Subscribers"},
{"value": "active", "label": "Active Users Only"},
{"value": "premium", "label": "Premium Members"},
],
),
FormField(
name="schedule",
label="Send Time",
field_type="datetime",
help_text="Leave empty to send immediately",
),
FormField(
name="confirm",
label="I understand this will send emails to real users",
field_type="checkbox",
required=True,
),
]
async def execute(self, data: dict[str, Any]) -> ActionResult:
count = await newsletter_service.send(
subject=data["subject"],
template=data["template"],
audience=data.get("audience", ["all"]),
scheduled_for=data.get("schedule"),
)
return ActionResult(
success=True,
message=f"Newsletter queued for {count} recipients!",
data={"recipient_count": count},
)
FormField Types¶
Type |
Description |
|---|---|
|
Single-line text input |
|
Multi-line text input |
|
Numeric input |
|
Email input with validation |
|
Password input (masked) |
|
Single-select dropdown |
|
Multi-select dropdown |
|
Boolean checkbox |
|
Radio button group |
|
Date picker |
|
Date and time picker |
|
File upload |
|
Hidden field |
FormField Options¶
FormField(
name="field_name", # Required: field identifier
label="Display Label", # Required: display text
field_type="text", # Input type
required=False, # Is field required?
default=None, # Default value
placeholder="", # Placeholder text
help_text="", # Help text below field
options=[], # Options for select/radio
validation={ # Validation rules
"min": 0,
"max": 100,
"pattern": r"^\d+$",
},
)
ActionResult¶
The execute method must return an ActionResult:
ActionResult(
success=True, # Success or failure
message="Operation completed", # User-facing message
redirect="/admin/users", # Optional redirect URL
data={"key": "value"}, # Optional response data
refresh=True, # Refresh current view?
)
Action Configuration¶
class MyAction(ActionView):
# Confirmation
confirmation_message = "Are you sure?" # Optional confirmation
requires_confirmation = True # Show confirmation dialog
# UI
submit_label = "Execute" # Submit button text
dangerous = False # Dangerous action styling
# Execution
success_redirect = "/admin/logs" # Redirect on success
run_in_background = False # Run asynchronously
timeout_seconds = 60 # Execution timeout
Custom Validation¶
Override validate_data for complex validation:
class DateRangeAction(ActionView):
form_fields = [
FormField(name="start_date", field_type="date", required=True),
FormField(name="end_date", field_type="date", required=True),
]
@classmethod
async def validate_data(cls, data: dict[str, Any]) -> tuple[bool, str | None]:
# First run default validation
is_valid, error = await super().validate_data(data)
if not is_valid:
return is_valid, error
# Custom validation
if data["start_date"] > data["end_date"]:
return False, "Start date must be before end date"
return True, None
PageView¶
PageView creates content pages within the admin panel. Use it for documentation, dashboards, help pages, or any custom content.
Static Content¶
For simple static pages, set the content directly:
from litestar_admin.views import PageView
class AboutPage(PageView):
name = "About"
icon = "info-circle"
content_type = "markdown"
content = """
# About This Admin Panel
Welcome to the administration interface for MyApp.
## Features
- User management with role-based access
- Content editing and publishing
- Analytics and reporting dashboard
- Audit logging for compliance
## Getting Help
Contact support at support@example.com
"""
Content Types¶
Type |
Description |
|---|---|
|
Markdown content (rendered to HTML) |
|
Raw HTML content |
|
Plain text |
|
Content fetched via |
|
Server-side template rendering |
Dynamic Content¶
For pages with dynamic data, use content_type = "dynamic" and override get_content:
class AnalyticsDashboard(PageView):
name = "Analytics"
icon = "chart-bar"
content_type = "dynamic"
refresh_interval = 60 # Auto-refresh every 60 seconds
async def get_content(self) -> dict[str, Any]:
users_count = await User.count()
orders_today = await Order.count_today()
revenue = await Order.total_revenue_today()
return {
"type": "dashboard",
"widgets": [
{
"type": "stat",
"title": "Total Users",
"value": users_count,
"icon": "users",
},
{
"type": "stat",
"title": "Orders Today",
"value": orders_today,
"icon": "shopping-cart",
"change": "+12%",
},
{
"type": "stat",
"title": "Revenue Today",
"value": f"${revenue:,.2f}",
"icon": "dollar-sign",
},
{
"type": "chart",
"title": "Weekly Signups",
"chart_type": "line",
"data": await get_signup_chart_data(),
},
],
}
Template-Based Pages¶
For complex layouts, use templates:
class SettingsPage(PageView):
name = "Settings"
icon = "cog"
content_type = "template"
template = "admin/settings.html"
template_context = {
"show_advanced": False,
}
async def get_template_context(
self,
connection: ASGIConnection,
) -> dict[str, Any]:
context = await super().get_template_context(connection)
context["current_user"] = connection.user
context["settings"] = await Settings.get_all()
return context
Page Layout Options¶
class WideContentPage(PageView):
layout = "full-width" # "default", "full-width", or "sidebar"
LinkView¶
LinkView adds external links to the admin navigation without any associated routes.
from litestar_admin.views import LinkView
class DocumentationLink(LinkView):
name = "Documentation"
icon = "book"
url = "https://docs.example.com"
target = "_blank" # Open in new tab
class APIDocsLink(LinkView):
name = "API Reference"
icon = "code"
category = "Developer"
url = "/api/docs"
target = "_self" # Open in same tab
Dynamic URLs¶
Override get_url for dynamic link generation:
class EnvironmentDocsLink(LinkView):
name = "Environment Docs"
icon = "external-link"
def get_url(self) -> str:
if settings.ENV == "production":
return "https://docs.prod.example.com"
return "https://docs.dev.example.com"
Conditional Links¶
Control link visibility based on user permissions:
class AdminDocsLink(LinkView):
name = "Admin Guide"
url = "https://internal.example.com/admin-guide"
@classmethod
async def is_accessible(cls, connection: ASGIConnection) -> bool:
user = getattr(connection, "user", None)
return user is not None and user.is_staff
EmbedView¶
EmbedView embeds external content or custom React components within the admin panel.
Iframe Embeds¶
Embed external dashboards, tools, or documentation:
from litestar_admin.views import EmbedView
class GrafanaMetrics(EmbedView):
name = "Metrics"
icon = "chart-line"
category = "Monitoring"
embed_type = "iframe"
embed_url = "https://grafana.example.com/d/abc123?orgId=1"
# Dimensions
height = "800px"
width = "100%"
min_height = "400px"
# Security
sandbox = "allow-scripts allow-same-origin"
allow = "fullscreen"
referrer_policy = "strict-origin-when-cross-origin"
# Behavior
loading = "lazy" # "eager" or "lazy"
show_toolbar = True # Show refresh/fullscreen buttons
refresh_interval = 300 # Auto-refresh every 5 minutes
Dynamic Iframe URLs¶
Generate URLs dynamically, for example to include auth tokens:
class UserSpecificDashboard(EmbedView):
name = "My Dashboard"
embed_type = "iframe"
embed_url = "https://dashboard.example.com"
async def get_embed_url(self, connection: ASGIConnection) -> str:
user = connection.user
token = await generate_dashboard_token(user.id)
return f"{self.embed_url}?user={user.id}&token={token}&theme=dark"
Component Embeds¶
Embed registered React components:
class ActivityFeed(EmbedView):
name = "Activity Feed"
icon = "activity"
embed_type = "component"
component_name = "ActivityFeed" # Must be registered in frontend
# Static props
props = {
"limit": 20,
"showTimestamps": True,
}
# Layout
layout = "sidebar" # "full", "sidebar", or "card"
async def get_props(self, connection: ASGIConnection) -> dict[str, Any]:
"""Dynamic props based on current user."""
user = connection.user
return {
"userId": user.id if user else None,
"limit": 20,
"showTimestamps": True,
"theme": user.preferences.get("theme", "dark") if user else "dark",
}
Iframe Security Options¶
Attribute |
Default |
Description |
|---|---|---|
|
|
Iframe sandbox restrictions |
|
|
Feature policy permissions |
|
|
Referrer policy |
|
|
Loading strategy |
Layout Options¶
Layout |
Description |
|---|---|
|
Full-page embed (default) |
|
Sidebar panel embed |
|
Card within dashboard |
Registering Views¶
Register all view types in your AdminConfig:
from litestar import Litestar
from litestar_admin import AdminPlugin, AdminConfig, ModelView
# Model views
class UserAdmin(ModelView, model=User):
column_list = ["id", "email", "name"]
class PostAdmin(ModelView, model=Post):
column_list = ["id", "title"]
# Custom views
class SettingsView(InMemoryView):
name = "Settings"
# ...
# Actions
class ClearCacheAction(ActionView):
name = "Clear Cache"
# ...
# Pages
class AboutPage(PageView):
name = "About"
# ...
# Links
class DocsLink(LinkView):
name = "Documentation"
url = "https://docs.example.com"
# Embeds
class MetricsEmbed(EmbedView):
name = "Metrics"
embed_url = "https://grafana.example.com"
# Register all views
app = Litestar(
plugins=[
AdminPlugin(
config=AdminConfig(
title="My Admin",
views=[
# Model views
UserAdmin,
PostAdmin,
# Custom views
SettingsView,
# Actions
ClearCacheAction,
# Pages
AboutPage,
# Links
DocsLink,
# Embeds
MetricsEmbed,
],
)
)
]
)
View Ordering¶
Control the order of views in the sidebar:
class FirstView(PageView):
name = "First"
order = 1 # Lower numbers appear first
class SecondView(PageView):
name = "Second"
order = 2
class LastView(PageView):
name = "Last"
order = 100
Grouping with Categories¶
Group views in the sidebar using categories:
class UserAdmin(ModelView, model=User):
category = "Users & Access"
class RoleAdmin(ModelView, model=Role):
category = "Users & Access"
class ProductAdmin(ModelView, model=Product):
category = "Store"
class ClearCacheAction(ActionView):
category = "Maintenance"
class BackupAction(ActionView):
category = "Maintenance"
Complete Example¶
Here’s a comprehensive example combining multiple view types:
from __future__ import annotations
from typing import Any
from litestar import Litestar
from litestar.connection import ASGIConnection
from litestar_admin import AdminPlugin, AdminConfig, ModelView
from litestar_admin.views import (
ActionView,
ActionResult,
ColumnDefinition,
EmbedView,
FormField,
LinkView,
PageView,
)
from litestar_admin.contrib.providers import InMemoryView, HTTPAPIView
from myapp.models import User, Post, AuditLog
# Model Views
class UserAdmin(ModelView, model=User):
name = "Users"
icon = "users"
category = "User Management"
column_list = ["id", "email", "name", "is_active", "created_at"]
column_searchable_list = ["email", "name"]
can_delete = False
class PostAdmin(ModelView, model=Post):
name = "Posts"
icon = "file-text"
category = "Content"
column_list = ["id", "title", "author", "status", "published_at"]
class AuditLogAdmin(ModelView, model=AuditLog):
name = "Audit Logs"
icon = "list"
category = "System"
can_create = False
can_edit = False
can_delete = False
# Custom View for App Settings
class AppSettingsView(InMemoryView):
name = "App Settings"
icon = "cog"
category = "Configuration"
pk_field = "key"
columns = [
ColumnDefinition(name="key", type="string", sortable=True),
ColumnDefinition(name="value", type="string"),
ColumnDefinition(name="description", type="text"),
]
_data = {
"site_name": {
"key": "site_name",
"value": "My Application",
"description": "Site name shown in header",
},
"maintenance_mode": {
"key": "maintenance_mode",
"value": "false",
"description": "Enable site-wide maintenance mode",
},
}
# External API View
class GitHubIssuesView(HTTPAPIView):
name = "GitHub Issues"
icon = "github"
category = "Integrations"
api_base_url = "https://api.github.com"
api_headers = {"Accept": "application/vnd.github.v3+json"}
list_endpoint = "/repos/owner/repo/issues"
items_key = None
columns = [
ColumnDefinition(name="number", type="integer", sortable=True),
ColumnDefinition(name="title", type="string", searchable=True),
ColumnDefinition(name="state", type="string", filterable=True),
ColumnDefinition(name="created_at", type="datetime", sortable=True),
]
# Admin Actions
class ClearCacheAction(ActionView):
name = "Clear Cache"
icon = "trash"
category = "Maintenance"
confirmation_message = "This will clear all cached data. Continue?"
form_fields = [
FormField(
name="cache_type",
label="Cache Type",
field_type="select",
required=True,
options=[
{"value": "all", "label": "All Caches"},
{"value": "user", "label": "User Cache"},
{"value": "session", "label": "Session Cache"},
],
),
]
async def execute(self, data: dict[str, Any]) -> ActionResult:
cache_type = data.get("cache_type", "all")
# await cache_service.clear(cache_type)
return ActionResult(
success=True,
message=f"Successfully cleared {cache_type} cache!",
refresh=True,
)
class ExportDataAction(ActionView):
name = "Export Data"
icon = "download"
category = "Data"
submit_label = "Generate Export"
form_fields = [
FormField(
name="format",
label="Export Format",
field_type="select",
required=True,
default="csv",
options=[
{"value": "csv", "label": "CSV"},
{"value": "json", "label": "JSON"},
{"value": "xlsx", "label": "Excel"},
],
),
FormField(
name="include_deleted",
label="Include deleted records",
field_type="checkbox",
),
]
async def execute(self, data: dict[str, Any]) -> ActionResult:
export_format = data.get("format", "csv")
# Generate export and get download URL
download_url = f"/admin/exports/download/123.{export_format}"
return ActionResult(
success=True,
message="Export generated successfully!",
redirect=download_url,
)
# Content Pages
class AboutPage(PageView):
name = "About"
icon = "info-circle"
content_type = "markdown"
content = """
# Admin Panel
Welcome to the administration interface.
## Quick Links
- [User Guide](/docs/user-guide)
- [API Documentation](/api/docs)
- [Support](mailto:support@example.com)
"""
class DashboardPage(PageView):
name = "Dashboard"
icon = "tachometer-alt"
content_type = "dynamic"
refresh_interval = 60
async def get_content(self) -> dict[str, Any]:
return {
"type": "dashboard",
"widgets": [
{"type": "stat", "title": "Users", "value": 1234},
{"type": "stat", "title": "Posts", "value": 567},
{"type": "stat", "title": "Revenue", "value": "$12,345"},
],
}
# External Links
class DocsLink(LinkView):
name = "Documentation"
icon = "book"
category = "Resources"
url = "https://docs.example.com"
target = "_blank"
class SupportLink(LinkView):
name = "Get Support"
icon = "life-ring"
category = "Resources"
url = "https://support.example.com"
target = "_blank"
# Embedded Dashboards
class MetricsEmbed(EmbedView):
name = "Server Metrics"
icon = "chart-line"
category = "Monitoring"
embed_type = "iframe"
embed_url = "https://grafana.example.com/d/server-metrics"
height = "600px"
sandbox = "allow-scripts allow-same-origin"
refresh_interval = 60
# Create the application
app = Litestar(
plugins=[
AdminPlugin(
config=AdminConfig(
title="MyApp Admin",
views=[
# High-priority pages first
DashboardPage,
# Model management
UserAdmin,
PostAdmin,
AuditLogAdmin,
# Custom data
AppSettingsView,
GitHubIssuesView,
# Actions
ClearCacheAction,
ExportDataAction,
# Info pages
AboutPage,
# Links
DocsLink,
SupportLink,
# Embeds
MetricsEmbed,
],
)
)
]
)
API Reference¶
For complete API documentation, see:
BaseAdminViewCustomViewActionViewPageViewLinkViewEmbedViewInMemoryViewJSONFileViewHTTPAPIView