openadmin-dev 0.4.0__tar.gz → 0.6.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.
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/PKG-INFO +1 -1
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/books.py +20 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/main.py +10 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/admin_page.py +7 -1
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/admin_panel.py +5 -0
- openadmin_dev-0.6.0/openadmin/fastapi/counters.py +17 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/section.py +4 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/__init__.py +2 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/__init__.py +2 -0
- openadmin_dev-0.6.0/openadmin/spec/components/icons.py +2003 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/page.py +3 -1
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/section.py +3 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/pyproject.toml +4 -1
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/ISSUE_TEMPLATE/bug.md +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/ISSUE_TEMPLATE/chore.md +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/ISSUE_TEMPLATE/feature.md +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/branch-name/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/dependency-cves/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/format/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/license/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/lint/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/security/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/spell-check/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/test/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/typecheck/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/unused-code/action.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/workflows/ci.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/workflows/publish.yml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.gitignore +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.python-version +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/LICENSE +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/LICENSES/AGPL-3.0-or-later.txt +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/Makefile +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/README.md +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/REUSE.toml +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/docs/assets/logo.png +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/__init__.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/__init__.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/analytics.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/authors.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/genres.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/health.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/overview.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/publishers.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/reports.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/tags.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/__init__.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/database.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/lifespan.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/models.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/seed.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/__init__.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/deps.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/__init__.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/action.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/area_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/bar_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/form.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/line_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/markdown.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/page_protocol.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/pagination_params.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/pie_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/stat.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/table.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/utils.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/action.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/area_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/bar_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/form.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/http_methods.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/line_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/markdown.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/pie_chart.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/property.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/property_type.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/stat.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/table.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/spec.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/tests/test_hello.py +0 -0
- {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/uv.lock +0 -0
|
@@ -69,6 +69,26 @@ class AddBookBody(BaseModel):
|
|
|
69
69
|
publisher_id: int | None = None
|
|
70
70
|
|
|
71
71
|
|
|
72
|
+
@page.table("Books by Author", description="Number of books per author")
|
|
73
|
+
async def get_books_by_author(session: AsyncSessionDep, pagination: PageDep):
|
|
74
|
+
stmt = (
|
|
75
|
+
select(models.Author, func.count(models.Book.id).label("book_count"))
|
|
76
|
+
.join(models.Book, models.Book.author_id == models.Author.id)
|
|
77
|
+
.group_by(models.Author.id)
|
|
78
|
+
.order_by(func.count(models.Book.id).desc())
|
|
79
|
+
.offset(pagination.page * pagination.per_page)
|
|
80
|
+
.limit(pagination.per_page)
|
|
81
|
+
)
|
|
82
|
+
result = await session.execute(stmt)
|
|
83
|
+
return [
|
|
84
|
+
{
|
|
85
|
+
"author": f"{author.first_name} {author.last_name}",
|
|
86
|
+
"book_count": book_count,
|
|
87
|
+
}
|
|
88
|
+
for author, book_count in result.all()
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
|
|
72
92
|
@page.form_post("Add Book", description="Add a new book to the catalog")
|
|
73
93
|
async def add_book(body: AddBookBody, session: AsyncSessionDep):
|
|
74
94
|
book = models.Book(**body.model_dump())
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
4
|
|
|
5
5
|
from fastapi import FastAPI
|
|
6
|
+
from fastapi.middleware.cors import CORSMiddleware
|
|
6
7
|
|
|
7
8
|
from openadmin.fastapi import AdminPanel
|
|
8
9
|
|
|
@@ -20,6 +21,15 @@ from .admin import (
|
|
|
20
21
|
from .lib import lifespan
|
|
21
22
|
|
|
22
23
|
app = FastAPI(lifespan=lifespan.lifespan)
|
|
24
|
+
|
|
25
|
+
app.add_middleware(
|
|
26
|
+
CORSMiddleware,
|
|
27
|
+
allow_origins=["*"],
|
|
28
|
+
allow_credentials=False,
|
|
29
|
+
allow_methods=["*"],
|
|
30
|
+
allow_headers=["*"],
|
|
31
|
+
)
|
|
32
|
+
|
|
23
33
|
admin_panel = AdminPanel(
|
|
24
34
|
"Book Library Admin", description="Manage and explore the book catalog"
|
|
25
35
|
)
|
|
@@ -9,7 +9,7 @@ from collections.abc import Callable
|
|
|
9
9
|
from fastapi import APIRouter, FastAPI
|
|
10
10
|
from openadmin import spec
|
|
11
11
|
|
|
12
|
-
from . import types
|
|
12
|
+
from . import counters, types
|
|
13
13
|
from .utils import extract_params
|
|
14
14
|
|
|
15
15
|
_SPECIAL_CHARS_RE = re.compile(r"[^a-zA-Z0-9\s]")
|
|
@@ -20,13 +20,17 @@ class AdminPage:
|
|
|
20
20
|
self,
|
|
21
21
|
name: str,
|
|
22
22
|
*,
|
|
23
|
+
icon: spec.Icon | None = None,
|
|
23
24
|
description: str | None = None,
|
|
24
25
|
) -> None:
|
|
25
26
|
self.name = name
|
|
26
27
|
self.description = description
|
|
28
|
+
self.icon: spec.Icon | None = icon
|
|
27
29
|
self.state: list[types.Component] = []
|
|
28
30
|
self.router = APIRouter(prefix=f"/{name.lower().replace(' ', '-')}")
|
|
29
31
|
self.key_repeat_count: dict[str, int] = {}
|
|
32
|
+
self.page_count = counters.get_next("page")
|
|
33
|
+
self.page_kebab_name, _ = self.__get_kebab_and_unique_name(self.name)
|
|
30
34
|
|
|
31
35
|
def get_page_spec(self, app: FastAPI) -> spec.Page:
|
|
32
36
|
components: list[spec.Component] = []
|
|
@@ -146,8 +150,10 @@ class AdminPage:
|
|
|
146
150
|
)
|
|
147
151
|
|
|
148
152
|
return spec.Page(
|
|
153
|
+
id=f"{self.page_kebab_name}-{self.page_count}",
|
|
149
154
|
name=self.name,
|
|
150
155
|
description=self.description,
|
|
156
|
+
icon=self.icon,
|
|
151
157
|
components=components,
|
|
152
158
|
)
|
|
153
159
|
|
|
@@ -28,8 +28,10 @@ class AdminPanel:
|
|
|
28
28
|
for section in self.state:
|
|
29
29
|
sections.append(
|
|
30
30
|
spec.Section(
|
|
31
|
+
id=section.id,
|
|
31
32
|
name=section.name,
|
|
32
33
|
description=section.description,
|
|
34
|
+
icon=section.icon,
|
|
33
35
|
pages=[p.get_page_spec(app) for p in section.pages],
|
|
34
36
|
)
|
|
35
37
|
)
|
|
@@ -46,6 +48,7 @@ class AdminPanel:
|
|
|
46
48
|
name: str,
|
|
47
49
|
*,
|
|
48
50
|
description: str | None = None,
|
|
51
|
+
icon: spec.Icon | None = None,
|
|
49
52
|
pages: List[AdminPage],
|
|
50
53
|
) -> None:
|
|
51
54
|
kebab_name = name.lower().replace(" ", "-")
|
|
@@ -59,8 +62,10 @@ class AdminPanel:
|
|
|
59
62
|
|
|
60
63
|
self.state.append(
|
|
61
64
|
types.Section(
|
|
65
|
+
id=kebab_name,
|
|
62
66
|
name=name,
|
|
63
67
|
description=description,
|
|
68
|
+
icon=icon,
|
|
64
69
|
pages=pages,
|
|
65
70
|
)
|
|
66
71
|
)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2026 OpenAdmin
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
__counters = {}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_next(key: Literal["page"]) -> int:
|
|
11
|
+
if key not in __counters:
|
|
12
|
+
__counters[key] = 1
|
|
13
|
+
|
|
14
|
+
value = __counters[key]
|
|
15
|
+
__counters[key] += 1
|
|
16
|
+
|
|
17
|
+
return value
|
|
@@ -5,11 +5,15 @@
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from typing import Sequence
|
|
7
7
|
|
|
8
|
+
from openadmin import spec
|
|
9
|
+
|
|
8
10
|
from .page_protocol import PageProtocol
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
@dataclass
|
|
12
14
|
class Section:
|
|
15
|
+
id: str
|
|
13
16
|
name: str
|
|
14
17
|
description: str | None
|
|
18
|
+
icon: spec.Icon | None
|
|
15
19
|
pages: Sequence[PageProtocol]
|
|
@@ -8,6 +8,7 @@ from .action import Action
|
|
|
8
8
|
from .area_chart import AreaChart
|
|
9
9
|
from .bar_chart import BarChart
|
|
10
10
|
from .form import Form
|
|
11
|
+
from .icons import Icon
|
|
11
12
|
from .line_chart import LineChart
|
|
12
13
|
from .markdown import Markdown
|
|
13
14
|
from .pie_chart import PieChart
|
|
@@ -32,4 +33,5 @@ __all__ = [
|
|
|
32
33
|
"Form",
|
|
33
34
|
"Property",
|
|
34
35
|
"PropertyType",
|
|
36
|
+
"Icon",
|
|
35
37
|
]
|