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.
Files changed (81) hide show
  1. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/PKG-INFO +1 -1
  2. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/books.py +20 -0
  3. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/main.py +10 -0
  4. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/admin_page.py +7 -1
  5. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/admin_panel.py +5 -0
  6. openadmin_dev-0.6.0/openadmin/fastapi/counters.py +17 -0
  7. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/section.py +4 -0
  8. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/__init__.py +2 -0
  9. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/__init__.py +2 -0
  10. openadmin_dev-0.6.0/openadmin/spec/components/icons.py +2003 -0
  11. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/page.py +3 -1
  12. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/section.py +3 -0
  13. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/pyproject.toml +4 -1
  14. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/ISSUE_TEMPLATE/bug.md +0 -0
  15. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/ISSUE_TEMPLATE/chore.md +0 -0
  16. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/ISSUE_TEMPLATE/feature.md +0 -0
  17. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/branch-name/action.yml +0 -0
  18. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/dependency-cves/action.yml +0 -0
  19. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/format/action.yml +0 -0
  20. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/license/action.yml +0 -0
  21. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/lint/action.yml +0 -0
  22. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/security/action.yml +0 -0
  23. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/spell-check/action.yml +0 -0
  24. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/test/action.yml +0 -0
  25. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/typecheck/action.yml +0 -0
  26. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/actions/unused-code/action.yml +0 -0
  27. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/workflows/ci.yml +0 -0
  28. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.github/workflows/publish.yml +0 -0
  29. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.gitignore +0 -0
  30. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/.python-version +0 -0
  31. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/LICENSE +0 -0
  32. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/LICENSES/AGPL-3.0-or-later.txt +0 -0
  33. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/Makefile +0 -0
  34. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/README.md +0 -0
  35. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/REUSE.toml +0 -0
  36. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/docs/assets/logo.png +0 -0
  37. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/__init__.py +0 -0
  38. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/__init__.py +0 -0
  39. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/analytics.py +0 -0
  40. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/authors.py +0 -0
  41. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/genres.py +0 -0
  42. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/health.py +0 -0
  43. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/overview.py +0 -0
  44. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/publishers.py +0 -0
  45. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/reports.py +0 -0
  46. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/admin/tags.py +0 -0
  47. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/__init__.py +0 -0
  48. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/database.py +0 -0
  49. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/lifespan.py +0 -0
  50. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/models.py +0 -0
  51. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/examples/lib/seed.py +0 -0
  52. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/__init__.py +0 -0
  53. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/deps.py +0 -0
  54. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/__init__.py +0 -0
  55. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/action.py +0 -0
  56. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/area_chart.py +0 -0
  57. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/bar_chart.py +0 -0
  58. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/form.py +0 -0
  59. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/line_chart.py +0 -0
  60. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/markdown.py +0 -0
  61. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/page_protocol.py +0 -0
  62. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/pagination_params.py +0 -0
  63. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/pie_chart.py +0 -0
  64. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/stat.py +0 -0
  65. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/types/table.py +0 -0
  66. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/fastapi/utils.py +0 -0
  67. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/action.py +0 -0
  68. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/area_chart.py +0 -0
  69. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/bar_chart.py +0 -0
  70. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/form.py +0 -0
  71. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/http_methods.py +0 -0
  72. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/line_chart.py +0 -0
  73. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/markdown.py +0 -0
  74. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/pie_chart.py +0 -0
  75. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/property.py +0 -0
  76. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/property_type.py +0 -0
  77. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/stat.py +0 -0
  78. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/components/table.py +0 -0
  79. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/openadmin/spec/spec.py +0 -0
  80. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/tests/test_hello.py +0 -0
  81. {openadmin_dev-0.4.0 → openadmin_dev-0.6.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openadmin-dev
3
- Version: 0.4.0
3
+ Version: 0.6.0
4
4
  Summary: Add your description here
5
5
  Project-URL: Homepage, https://github.com/openadmin-team/openadmin-py
6
6
  Project-URL: Issues, https://github.com/openadmin-team/openadmin-py/issues
@@ -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 .components import (
8
8
  BarChart,
9
9
  Component,
10
10
  Form,
11
+ Icon,
11
12
  LineChart,
12
13
  Markdown,
13
14
  PieChart,
@@ -38,4 +39,5 @@ __all__ = [
38
39
  "Stat",
39
40
  "Table",
40
41
  "Markdown",
42
+ "Icon",
41
43
  ]
@@ -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
  ]