brilliance-admin 0.43.7__py3-none-any.whl → 0.44.12__py3-none-any.whl
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.
- brilliance_admin/api/routers.py +2 -2
- brilliance_admin/api/views/autocomplete.py +1 -1
- brilliance_admin/api/views/{graphs.py → dashboard.py} +5 -5
- brilliance_admin/api/views/table.py +7 -6
- brilliance_admin/exceptions.py +1 -0
- brilliance_admin/integrations/sqlalchemy/auth.py +1 -2
- brilliance_admin/integrations/sqlalchemy/autocomplete.py +6 -1
- brilliance_admin/integrations/sqlalchemy/fields.py +22 -9
- brilliance_admin/integrations/sqlalchemy/table/create.py +4 -1
- brilliance_admin/integrations/sqlalchemy/table/delete.py +1 -1
- brilliance_admin/integrations/sqlalchemy/table/list.py +42 -12
- brilliance_admin/integrations/sqlalchemy/table/retrieve.py +33 -14
- brilliance_admin/integrations/sqlalchemy/table/update.py +6 -1
- brilliance_admin/locales/en.yml +12 -5
- brilliance_admin/locales/ru.yml +12 -6
- brilliance_admin/schema/__init__.py +3 -3
- brilliance_admin/schema/admin_schema.py +31 -23
- brilliance_admin/schema/category.py +87 -12
- brilliance_admin/schema/dashboard/__init__.py +1 -0
- brilliance_admin/schema/dashboard/category_dashboard.py +87 -0
- brilliance_admin/schema/table/category_table.py +13 -8
- brilliance_admin/schema/table/fields/base.py +65 -11
- brilliance_admin/schema/table/fields_schema.py +7 -1
- brilliance_admin/static/{index-BnnESruI.js → index-8ahvKI6W.js} +184 -184
- brilliance_admin/static/{index-vlBToOhT.css → index-B8JOx1Ps.css} +1 -1
- brilliance_admin/templates/index.html +2 -2
- brilliance_admin/translations.py +3 -0
- brilliance_admin/utils.py +38 -0
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.12.dist-info}/METADATA +56 -108
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.12.dist-info}/RECORD +33 -34
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.12.dist-info}/WHEEL +1 -1
- brilliance_admin-0.44.12.dist-info/licenses/LICENSE +21 -0
- brilliance_admin/schema/graphs/__init__.py +0 -1
- brilliance_admin/schema/graphs/category_graphs.py +0 -51
- brilliance_admin/schema/group.py +0 -67
- brilliance_admin-0.43.7.dist-info/licenses/LICENSE +0 -17
- {brilliance_admin-0.43.7.dist-info → brilliance_admin-0.44.12.dist-info}/top_level.txt +0 -0
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
<link rel="icon" href="{{ favicon_image }}" />
|
|
14
14
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
15
15
|
<title>{{ title }}</title>
|
|
16
|
-
<script type="module" crossorigin src="/admin/static/index-
|
|
17
|
-
<link rel="stylesheet" crossorigin href="/admin/static/index-
|
|
16
|
+
<script type="module" crossorigin src="/admin/static/index-8ahvKI6W.js"></script>
|
|
17
|
+
<link rel="stylesheet" crossorigin href="/admin/static/index-B8JOx1Ps.css">
|
|
18
18
|
</head>
|
|
19
19
|
|
|
20
20
|
<body>
|
brilliance_admin/translations.py
CHANGED
|
@@ -21,6 +21,9 @@ class TranslateText(DataclassBase):
|
|
|
21
21
|
def __init__(self, slug: str):
|
|
22
22
|
self.slug = slug
|
|
23
23
|
|
|
24
|
+
def __hash__(self):
|
|
25
|
+
return hash(self.slug)
|
|
26
|
+
|
|
24
27
|
@pydantic.model_serializer(mode='plain')
|
|
25
28
|
def serialize_model(self, info: pydantic.SerializationInfo) -> str:
|
|
26
29
|
ctx = info.context or {}
|
brilliance_admin/utils.py
CHANGED
|
@@ -5,6 +5,7 @@ from typing import Any, Dict, Protocol
|
|
|
5
5
|
|
|
6
6
|
import yaml
|
|
7
7
|
from pydantic import TypeAdapter
|
|
8
|
+
from pydantic.fields import FieldInfo
|
|
8
9
|
from pydantic_core import core_schema
|
|
9
10
|
|
|
10
11
|
|
|
@@ -37,6 +38,43 @@ class DeserializeAction:
|
|
|
37
38
|
FILTERS = 3
|
|
38
39
|
|
|
39
40
|
|
|
41
|
+
class KwargsInitMixin:
|
|
42
|
+
"""
|
|
43
|
+
Принимает только аргументы, объявленные в аннотациях.
|
|
44
|
+
Применяет default / default_factory из Field.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self, **kwargs):
|
|
48
|
+
annotations = {}
|
|
49
|
+
for cls in type(self).__mro__:
|
|
50
|
+
annotations.update(getattr(cls, '__annotations__', {}))
|
|
51
|
+
|
|
52
|
+
allowed = set(annotations.keys())
|
|
53
|
+
|
|
54
|
+
for key, value in kwargs.items():
|
|
55
|
+
if key not in allowed:
|
|
56
|
+
raise AttributeError(
|
|
57
|
+
f'{type(self).__name__} has no field "{key}". '
|
|
58
|
+
f'Allowed fields: {sorted(allowed)}'
|
|
59
|
+
)
|
|
60
|
+
setattr(self, key, value)
|
|
61
|
+
|
|
62
|
+
self._apply_field_defaults()
|
|
63
|
+
|
|
64
|
+
def _apply_field_defaults(self):
|
|
65
|
+
for cls in type(self).__mro__:
|
|
66
|
+
for name, value in cls.__dict__.items():
|
|
67
|
+
if not isinstance(value, FieldInfo):
|
|
68
|
+
continue
|
|
69
|
+
|
|
70
|
+
# если в инстансе всё ещё FieldInfo — заменить
|
|
71
|
+
if getattr(self, name, None) is value:
|
|
72
|
+
if value.default_factory is not None:
|
|
73
|
+
setattr(self, name, value.default_factory())
|
|
74
|
+
elif value.default is not None:
|
|
75
|
+
setattr(self, name, value.default)
|
|
76
|
+
|
|
77
|
+
|
|
40
78
|
class DataclassBase:
|
|
41
79
|
def model_dump(self, *args, **kwargs) -> dict:
|
|
42
80
|
adapter = TypeAdapter(type(self))
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: brilliance-admin
|
|
3
|
-
Version: 0.
|
|
4
|
-
Summary: Simple and lightweight
|
|
5
|
-
License-Expression:
|
|
3
|
+
Version: 0.44.12
|
|
4
|
+
Summary: Simple and lightweight data managment framework powered by FastAPI and Vue3 Vuetify all-in-one. Some call it heavenly in its brilliance.
|
|
5
|
+
License-Expression: MIT
|
|
6
6
|
Requires-Python: >=3.10
|
|
7
7
|
Description-Content-Type: text/markdown
|
|
8
8
|
License-File: LICENSE
|
|
@@ -16,6 +16,9 @@ Requires-Dist: faker>=38.2.0; extra == "example"
|
|
|
16
16
|
Requires-Dist: pyjwt>=2.10.1; extra == "example"
|
|
17
17
|
Requires-Dist: structlog>=25.5.0; extra == "example"
|
|
18
18
|
Requires-Dist: rich>=14.2.0; extra == "example"
|
|
19
|
+
Requires-Dist: asyncpg>=0.31.0; extra == "example"
|
|
20
|
+
Requires-Dist: pydantic-settings>=2.12.0; extra == "example"
|
|
21
|
+
Requires-Dist: twine; extra == "example"
|
|
19
22
|
Provides-Extra: tests
|
|
20
23
|
Requires-Dist: pytest>=8.4.2; extra == "tests"
|
|
21
24
|
Requires-Dist: pytest-asyncio>=1.2.0; extra == "tests"
|
|
@@ -37,58 +40,76 @@ Dynamic: license-file
|
|
|
37
40
|
[](https://pypi.org/project/brilliance-admin/)
|
|
38
41
|
[](https://github.com/brilliance-admin/backend-python/actions)
|
|
39
42
|
|
|
40
|
-
Simple and lightweight
|
|
43
|
+
Simple and lightweight data management framework powered by `FastAPI` and `Vue3` `Vuetify` all-in-one. \
|
|
41
44
|
Integrated with `SQLAlchemy`. Inspaired by Django Admin and DRF.\
|
|
42
45
|
_Some call it heavenly in its brilliance._
|
|
43
46
|
|
|
44
|
-
### [Live Demo](https://brilliance-admin.com/) | [Demo Sources](https://github.com/brilliance-admin/backend-python/tree/main/example) | Documentation
|
|
47
|
+
### [Live Demo](https://brilliance-admin.com/) | [Demo Sources](https://github.com/brilliance-admin/backend-python/tree/main/example) | [Documentation](https://docs.brilliance-admin.com/)
|
|
45
48
|
|
|
46
49
|
<img src="https://github.com/brilliance-admin/backend-python/blob/main/screenshots/websitemockupgenerator.png?raw=true"
|
|
47
50
|
alt="Preview">
|
|
48
51
|
|
|
49
52
|
</div>
|
|
50
53
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
-
|
|
54
|
+
### Brilliance Admin provides
|
|
55
|
+
|
|
56
|
+
A quick way to create a data management interface using:
|
|
57
|
+
|
|
58
|
+
- Admin page - endpoint with a prebuilt SPA [frontend Vue3 + Vuetify](https://github.com/brilliance-admin/frontend) <br>
|
|
59
|
+
This endpoint can be added to any ASGI compatable backend. For existing project or standalone admin app.
|
|
60
|
+
- API to fetch the UI JSON schema
|
|
61
|
+
- API methods for that UI to work with (to read and modify data)
|
|
62
|
+
|
|
63
|
+
<details open>
|
|
64
|
+
<summary><h2>Screenshots</h2></summary>
|
|
65
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/login.png?raw=true"/></div>
|
|
66
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/table.png?raw=true"/></div>
|
|
67
|
+
<div align="center"><img src="https://github.com/brilliance-admin/.github/blob/main/screenshots/charts.png?raw=true"/></div>
|
|
68
|
+
</details>
|
|
69
|
+
|
|
70
|
+
## Key ideas
|
|
71
|
+
|
|
72
|
+
- **API Oriented** <br>
|
|
73
|
+
Data generation/updating API separated from rendering fontend with zero hardcode, this makes it possible to have a single frontend with multiple backend implementations in different languages and makes test coverage easier.
|
|
74
|
+
- **Rich visualization** <br>
|
|
56
75
|
Providing rich and convenient ways to display and manage data (tables, charts, etc) from any data source.
|
|
57
|
-
- **
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
- **UI JSON Schema** <br>
|
|
77
|
+
Represents the data describing the structure of entire admin panel UI. <br>
|
|
78
|
+
You only need to specify what should be rendered. The frontend will display it and automatically request data from the backend for rendering or updates.
|
|
79
|
+
- **ORM** <br>
|
|
80
|
+
Automatic generation from ORM for schema UI frontend and backend methods for CRUD operations.
|
|
81
|
+
- **Minimal boilerplate** <br>
|
|
60
82
|
Focused on simplified, but rich configuration.
|
|
61
83
|
|
|
62
|
-
|
|
63
|
-
- After authentication, the user receives the admin panel schema, and the frontend renders it
|
|
64
|
-
- The frontend communicates with the backend via API to fetch and modify data
|
|
65
|
-
|
|
66
|
-
### Features:
|
|
84
|
+
## Features
|
|
67
85
|
|
|
68
86
|
* Tables with full CRUD support, including filtering, sorting, and pagination.
|
|
69
87
|
* Ability to define custom table actions with forms, response messages, and file downloads.
|
|
70
88
|
* Graphs via ChartJS
|
|
71
89
|
* Localization support
|
|
72
90
|
* Adapted for different screen sizes and mobile devices
|
|
73
|
-
*
|
|
91
|
+
* Auth via any account data source
|
|
74
92
|
|
|
75
93
|
**Integrations:**
|
|
94
|
+
|
|
76
95
|
* **SQLAlchemy** - schema autogeneration for tables + CRUD operations + authorization
|
|
77
96
|
|
|
78
97
|
**Planned:**
|
|
98
|
+
|
|
79
99
|
* Dashboard features
|
|
80
100
|
* Role-based access permissions system via interface
|
|
81
101
|
* Backend interface for storing and viewing action history in the admin interface
|
|
82
102
|
* Nested data support for creation and detail views (inline editing), nested CRUD workflows
|
|
83
103
|
* Django ORM integration
|
|
104
|
+
* Support for Oauth providers
|
|
84
105
|
|
|
85
|
-
##
|
|
86
|
-
|
|
87
|
-
Installation:
|
|
106
|
+
## Installation:
|
|
88
107
|
``` shell
|
|
89
108
|
pip install brilliance-admin
|
|
90
109
|
```
|
|
91
110
|
|
|
111
|
+
## Usage example
|
|
112
|
+
|
|
92
113
|
You need to generate `AdminSchema` instance:
|
|
93
114
|
``` python
|
|
94
115
|
from brilliance_admin import schema
|
|
@@ -101,11 +122,9 @@ class CategoryExample(schema.CategoryTable):
|
|
|
101
122
|
admin_schema = schema.AdminSchema(
|
|
102
123
|
title='Admin Panel',
|
|
103
124
|
auth=YourAdminAuthentication(),
|
|
104
|
-
|
|
105
|
-
schema.
|
|
125
|
+
categories=[
|
|
126
|
+
schema.Category(
|
|
106
127
|
slug='example',
|
|
107
|
-
title='Example',
|
|
108
|
-
icon='mdi-star',
|
|
109
128
|
categories=[
|
|
110
129
|
CategoryExample(),
|
|
111
130
|
]
|
|
@@ -115,98 +134,27 @@ admin_schema = schema.AdminSchema(
|
|
|
115
134
|
|
|
116
135
|
admin_app = admin_schema.generate_app()
|
|
117
136
|
|
|
118
|
-
# Your FastAPI app
|
|
137
|
+
# Your FastAPI app (Any ASGI framework can be used)
|
|
119
138
|
app = FastAPI()
|
|
120
139
|
app.mount('/admin', admin_app)
|
|
121
140
|
```
|
|
122
141
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
Supports automatic schema generation for CRUD tables:
|
|
126
|
-
|
|
127
|
-
``` python
|
|
128
|
-
category = sqlalchemy.SQLAlchemyAdmin(db_async_session=async_sessionmaker, model=Terminal)
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
> [!NOTE]
|
|
132
|
-
> If `table_schema` is not specified, it will be generated automatically with all discovered fields and relationships
|
|
133
|
-
|
|
134
|
-
Now, the `category` instance can be passed to `categories`.
|
|
135
|
-
|
|
136
|
-
### DRF class style schema
|
|
137
|
-
|
|
138
|
-
``` python
|
|
139
|
-
from brilliance_admin import sqlalchemy
|
|
140
|
-
from brilliance_admin.translations import TranslateText as _
|
|
141
|
-
|
|
142
|
-
from your_project.models import Terminal
|
|
143
|
-
|
|
142
|
+
For more details, check out our [how-to-start documentation](https://docs.brilliance-admin.com/how-to-start/)
|
|
144
143
|
|
|
145
|
-
|
|
146
|
-
model = Terminal
|
|
147
|
-
fields = ['id', 'created_at']
|
|
148
|
-
created_at = schema.DateTimeField(range=True)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
class TerminalSchema(sqlalchemy.SQLAlchemyFieldsSchema):
|
|
152
|
-
model = Terminal
|
|
153
|
-
list_display = ['id', 'merchant_id']
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
class TerminalAdmin(sqlalchemy.SQLAlchemyAdmin):
|
|
157
|
-
db_async_session = async_sessionmaker
|
|
158
|
-
model = Terminal
|
|
159
|
-
title = _('terminals')
|
|
160
|
-
icon = 'mdi-console-network-outline'
|
|
161
|
-
|
|
162
|
-
ordering_fields = ['id']
|
|
163
|
-
search_fields = ['id', 'title']
|
|
164
|
-
|
|
165
|
-
table_schema = TerminalSchema()
|
|
166
|
-
table_filters = TerminalFiltersSchema()
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
category = TerminalAdmin()
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Can be used both via inheritance and instancing
|
|
173
|
-
|
|
174
|
-
Optionally, functional-style generation can be used to reduce boilerplate code
|
|
175
|
-
|
|
176
|
-
Availiable for `SQLAlchemyAdmin` and `SQLAlchemyFieldsSchema`
|
|
177
|
-
|
|
178
|
-
``` python
|
|
179
|
-
category = sqlalchemy.SQLAlchemyAdmin(
|
|
180
|
-
db_async_session=async_sessionmaker,
|
|
181
|
-
model=Terminal,
|
|
182
|
-
|
|
183
|
-
table_schema = sqlalchemy.SQLAlchemyFieldsSchema(
|
|
184
|
-
model=Terminal,
|
|
185
|
-
list_display=['id', 'merchant_id'],
|
|
186
|
-
),
|
|
187
|
-
table_filters = sqlalchemy.SQLAlchemyFieldsSchema(
|
|
188
|
-
model=Terminal,
|
|
189
|
-
fields=['id', 'created_at'],
|
|
190
|
-
created_at=schema.DateTimeField(range=True),
|
|
191
|
-
),
|
|
192
|
-
)
|
|
193
|
-
```
|
|
144
|
+
## Comparison of Similar Projects
|
|
194
145
|
|
|
195
|
-
|
|
146
|
+
The project closest in concept is [React Admin](https://github.com/marmelab/react-admin). <br>
|
|
147
|
+
It is an SPA frontend that store the schema UI inside and works with separate API backend providers.
|
|
196
148
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
secret='auth_secret',
|
|
200
|
-
db_async_session=async_session,
|
|
201
|
-
user_model=User,
|
|
202
|
-
)
|
|
203
|
-
```
|
|
149
|
+
The key difference of Brilliance Admin is that its all-in-one. <br>
|
|
150
|
+
It is more focused on rapid setup for data management, without the need to work with frontend configuration, while it still available.
|
|
204
151
|
|
|
205
|
-
## Comparison of Similar Projects
|
|
152
|
+
## Comparison of Similar Python Projects
|
|
206
153
|
|
|
207
154
|
| Criterion | Brilliance Admin | Django Admin | FastAPI Admin | Starlette Admin | SQLAdmin |
|
|
208
|
-
|
|
209
|
-
| Base framework | FastAPI | Django | FastAPI | Starlette
|
|
155
|
+
|---------|------------------|--------------|---------------|-----------------|----------|
|
|
156
|
+
| Base framework | FastAPI | Django | FastAPI | Starlette | FastAPI |
|
|
157
|
+
| ASGI compatible | Yes | Partial | Yes | Yes | Yes |
|
|
210
158
|
| Rendering model | Prebuilt Vue 3 + Vuetify SPA + Jinja2 | Server-side Django templates | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Bootstrap |
|
|
211
159
|
| Frontend architecture | Separate frontend (SPA) | Classic server-rendered UI | Server-rendered UI with JS interactivity | Server-rendered UI with JS interactivity | Server-rendered UI |
|
|
212
160
|
| Data source | Any source + SQLAlchemy | Django ORM | Tortoise ORM | Any source + SQLAlchemy, MongoDB | SQLAlchemy |
|
|
@@ -1,51 +1,50 @@
|
|
|
1
1
|
brilliance_admin/__init__.py,sha256=qxGzLVhFNm2FKL2lVt7bEFb6pTPqyXEQvUsDfyfv6SM,183
|
|
2
2
|
brilliance_admin/auth.py,sha256=d57XRfLJIbOosLP1-0SCFkePPT8M5WhLcwxu4yW92RA,673
|
|
3
3
|
brilliance_admin/docs.py,sha256=fKeJKuiCCi1jHRmNcmkuDD6_2di7bwc6-w8V1VCTu0s,1231
|
|
4
|
-
brilliance_admin/exceptions.py,sha256=
|
|
5
|
-
brilliance_admin/translations.py,sha256=
|
|
6
|
-
brilliance_admin/utils.py,sha256=
|
|
4
|
+
brilliance_admin/exceptions.py,sha256=CJGvpo7EiaX3RVAEUDpwgH_Tuw8kY7tMy57pVcnBxak,947
|
|
5
|
+
brilliance_admin/translations.py,sha256=r5xy3Iara_7m2E7rgG8goPFDcKdPLUGAKIWIt6TdulA,3906
|
|
6
|
+
brilliance_admin/utils.py,sha256=M_0WANlb-1NW4aOA33MxOgoRx0GIVJ6w6PCGKAwmflk,5971
|
|
7
7
|
brilliance_admin/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
-
brilliance_admin/api/routers.py,sha256=
|
|
8
|
+
brilliance_admin/api/routers.py,sha256=S8IV7JxA1wLspYn3qxESMI3Qt6UhQK-Gy0PsZi8hcwQ,819
|
|
9
9
|
brilliance_admin/api/utils.py,sha256=ezvHK49OlpCdT9fLB41Y1nswZDLdzC3zTcQtGtuTYUk,999
|
|
10
10
|
brilliance_admin/api/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
11
|
brilliance_admin/api/views/auth.py,sha256=Qmd9KuFqCeNhQukYl0W62kcUYPMtgMekjkaTvz1AArM,1133
|
|
12
|
-
brilliance_admin/api/views/autocomplete.py,sha256=
|
|
13
|
-
brilliance_admin/api/views/
|
|
12
|
+
brilliance_admin/api/views/autocomplete.py,sha256=lpFDq46OCuiPhkUedv4y6GmJQVy3iX4P-di_-GMzabY,1516
|
|
13
|
+
brilliance_admin/api/views/dashboard.py,sha256=tLFdbKrePH-A91HNCN4F_FXdlRQ1tA9D2tGLvzDOoFM,1389
|
|
14
14
|
brilliance_admin/api/views/index.py,sha256=DkMshrs5zmqpbbF9G2RhqeLGFKMrkrAmQ6nnba7aLl8,1400
|
|
15
15
|
brilliance_admin/api/views/schema.py,sha256=MS9v9Qy3cRO9gGs4uW2PNRBS6Uw48sLRGRe49jnJ2yM,1019
|
|
16
16
|
brilliance_admin/api/views/settings.py,sha256=2A9suZQONEtW9LkFban29Fe5ipQaaGT0CzpxnbuotJQ,1166
|
|
17
|
-
brilliance_admin/api/views/table.py,sha256=
|
|
17
|
+
brilliance_admin/api/views/table.py,sha256=dLo_ic9LPeAvkeelbkHZs9oC9g9ZlXPPMiQMszlwDIQ,5979
|
|
18
18
|
brilliance_admin/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
19
19
|
brilliance_admin/integrations/sqlalchemy/__init__.py,sha256=AmQHOvegS6_uaE4xYDHzRMdA9PyHn0cCt1s1IWc9G2U,318
|
|
20
|
-
brilliance_admin/integrations/sqlalchemy/auth.py,sha256=
|
|
21
|
-
brilliance_admin/integrations/sqlalchemy/autocomplete.py,sha256=
|
|
22
|
-
brilliance_admin/integrations/sqlalchemy/fields.py,sha256=
|
|
20
|
+
brilliance_admin/integrations/sqlalchemy/auth.py,sha256=N9CjFfnXmKeNbJBxHMDlbPaTQPmYWlYTz_73PYBkaNk,4931
|
|
21
|
+
brilliance_admin/integrations/sqlalchemy/autocomplete.py,sha256=IKZwdjb5tM_pA5PBUhwYo4n_8nEfy_WcSu8Yu4ftarI,1572
|
|
22
|
+
brilliance_admin/integrations/sqlalchemy/fields.py,sha256=7D0E4-12rqraqHek2yNuHzRdO7hhxjp0edhJu-mTnWQ,9897
|
|
23
23
|
brilliance_admin/integrations/sqlalchemy/fields_schema.py,sha256=7WkOrt5dVvrsZppNZEZS8QaQPMSrfcWChwOaOFSRVOg,11419
|
|
24
24
|
brilliance_admin/integrations/sqlalchemy/table/__init__.py,sha256=g_in2pLTi8UQnT5uNFA8mLW5mxlT84irQ7yVaP_OSS4,605
|
|
25
25
|
brilliance_admin/integrations/sqlalchemy/table/base.py,sha256=-osqhTvqE7YcBxsAjqIUMWyYk1df04GIDmdvtieTXcg,4885
|
|
26
|
-
brilliance_admin/integrations/sqlalchemy/table/create.py,sha256=
|
|
27
|
-
brilliance_admin/integrations/sqlalchemy/table/delete.py,sha256=
|
|
28
|
-
brilliance_admin/integrations/sqlalchemy/table/list.py,sha256=
|
|
29
|
-
brilliance_admin/integrations/sqlalchemy/table/retrieve.py,sha256=
|
|
30
|
-
brilliance_admin/integrations/sqlalchemy/table/update.py,sha256=
|
|
31
|
-
brilliance_admin/locales/en.yml,sha256=
|
|
32
|
-
brilliance_admin/locales/ru.yml,sha256=
|
|
33
|
-
brilliance_admin/schema/__init__.py,sha256=
|
|
34
|
-
brilliance_admin/schema/admin_schema.py,sha256=
|
|
35
|
-
brilliance_admin/schema/category.py,sha256=
|
|
36
|
-
brilliance_admin/schema/
|
|
37
|
-
brilliance_admin/schema/
|
|
38
|
-
brilliance_admin/schema/graphs/category_graphs.py,sha256=2nj_oiAoGXwGhc-gNVNFMNKDCkCdUWVn6u9CRCsb2DA,1513
|
|
26
|
+
brilliance_admin/integrations/sqlalchemy/table/create.py,sha256=MJauwTe9armKyfGAdurVNrLKMAdC6tpHiEgAelgMCno,2871
|
|
27
|
+
brilliance_admin/integrations/sqlalchemy/table/delete.py,sha256=kcDEM7WDNu3lFdfdltN7nO2zQKHW3TQCYvGn1QcAyZc,755
|
|
28
|
+
brilliance_admin/integrations/sqlalchemy/table/list.py,sha256=Y76B5CFqQb2nfV0i0MrMrK3_kn9cyDvx10gEF8smrIA,8008
|
|
29
|
+
brilliance_admin/integrations/sqlalchemy/table/retrieve.py,sha256=EKwGH8Mz3Jd-uR43WibD3hFiZVGK_ra_5Cu5XeoEf6Y,3508
|
|
30
|
+
brilliance_admin/integrations/sqlalchemy/table/update.py,sha256=NxcYPqRZbm_BM-4QHzEbhgAhYSs3SXzYMMzKCalqahU,3800
|
|
31
|
+
brilliance_admin/locales/en.yml,sha256=YBjkq2Tm0KjXKOMgnIM5etO42Pkm8mDdQlvmpITwsA4,1453
|
|
32
|
+
brilliance_admin/locales/ru.yml,sha256=9MKJaJyx6dALP6CQkLQMJvgZdp8nwgnBxDsRZiYhlnc,2052
|
|
33
|
+
brilliance_admin/schema/__init__.py,sha256=H5UFO5dub_k5id8WdGRVy9G8RnqZuBSjw9XgPafj1VQ,293
|
|
34
|
+
brilliance_admin/schema/admin_schema.py,sha256=SGdNuYUKrwAc6SA4RYh8TgSrod5RuY7lpXKzmY1SHZ4,6812
|
|
35
|
+
brilliance_admin/schema/category.py,sha256=UTnUexbCHe9vfwi3ygX34YkLAH2ixfMWqe4H6xos0fI,6604
|
|
36
|
+
brilliance_admin/schema/dashboard/__init__.py,sha256=RxE5nNs5X3iWGXBOA518hFyJMSRLEcXr0PNb8HZrjxs,50
|
|
37
|
+
brilliance_admin/schema/dashboard/category_dashboard.py,sha256=rsEuWLpcfcrnzMeKIQCMFDYNF9H7LEfqEKlm63Sh7PE,2650
|
|
39
38
|
brilliance_admin/schema/table/__init__.py,sha256=vuRw8HBuak2LaTZi2dNn5YOrJPalQps-O3Ht-d0AZV4,378
|
|
40
39
|
brilliance_admin/schema/table/admin_action.py,sha256=0ymRL9DKkBK-AF6wKy7K9R4hkmblh55eHuZA_rjO1Lk,2018
|
|
41
|
-
brilliance_admin/schema/table/category_table.py,sha256=
|
|
42
|
-
brilliance_admin/schema/table/fields_schema.py,sha256=
|
|
40
|
+
brilliance_admin/schema/table/category_table.py,sha256=AHR6fatZTdRKvUnks7DzQm0V0OwID-59khTxosEXoHE,6817
|
|
41
|
+
brilliance_admin/schema/table/fields_schema.py,sha256=E6U0oLREyCU-8HnwNB8Sf40al2bIzgs0-g5fOpqbQkw,8475
|
|
43
42
|
brilliance_admin/schema/table/table_models.py,sha256=xidraifRYbXGkiVLn6dJ96dkOhW8-22ynE-fbiOjfAU,1018
|
|
44
43
|
brilliance_admin/schema/table/fields/__init__.py,sha256=RW-sIFTAaSQo4mMR6iWtnefogWPjmg6KAsDwe9mKW1k,291
|
|
45
|
-
brilliance_admin/schema/table/fields/base.py,sha256=
|
|
44
|
+
brilliance_admin/schema/table/fields/base.py,sha256=rSVTsY1ph9ix33NiPslDjPjnwWvHwNtvt90FAByE4mQ,10243
|
|
46
45
|
brilliance_admin/schema/table/fields/function_field.py,sha256=4fm9kS8zpBG5oqp9sA81NQDHiqvU0BQmpf-wjkTuuwM,1780
|
|
47
|
-
brilliance_admin/static/index-
|
|
48
|
-
brilliance_admin/static/index-
|
|
46
|
+
brilliance_admin/static/index-8ahvKI6W.js,sha256=UVxVir-ZeOS8j83b7hAD-ZCanD7TO3vrNMgnclPFlP8,3209593
|
|
47
|
+
brilliance_admin/static/index-B8JOx1Ps.css,sha256=tvExD9r6ozGNJwjveAsdguzJ7Eab2iT-Z9coevdEtK0,984316
|
|
49
48
|
brilliance_admin/static/materialdesignicons-webfont-CYDMK1kx.woff2,sha256=5S1g9kJnzaoIQitQurXUW9NeZisDua91F5zq4ArF_Is,385360
|
|
50
49
|
brilliance_admin/static/materialdesignicons-webfont-CgCzGbLl.woff,sha256=SNPuxqtw3HoZCPm6LyCOClhxi57hbj9qvbXbT0Yfolg,561776
|
|
51
50
|
brilliance_admin/static/materialdesignicons-webfont-D3kAzl71.ttf,sha256=vXJaejiTnltZkE4benJlkZ7OwlYWbs5p1RXCEAUWWQc,1243500
|
|
@@ -66,9 +65,9 @@ brilliance_admin/static/tinymce/plugins/accordion/css/accordion.css,sha256=u5UQk
|
|
|
66
65
|
brilliance_admin/static/tinymce/plugins/codesample/css/prism.css,sha256=exAdMtHbvwW7-DEs567MX65Fq1aJQTfREP5pw8gW-AY,1736
|
|
67
66
|
brilliance_admin/static/tinymce/plugins/customLink/plugin.js,sha256=illBNpnHDkBsLG6wo_jDPF6z7CGnO1MQWUoDwZKy6vQ,5589
|
|
68
67
|
brilliance_admin/static/tinymce/plugins/customLink/css/link.css,sha256=gh5nvY8Z92hJfCEBPnIm4jIPCcKKbJnab-30oIfX7Hc,56
|
|
69
|
-
brilliance_admin/templates/index.html,sha256=
|
|
70
|
-
brilliance_admin-0.
|
|
71
|
-
brilliance_admin-0.
|
|
72
|
-
brilliance_admin-0.
|
|
73
|
-
brilliance_admin-0.
|
|
74
|
-
brilliance_admin-0.
|
|
68
|
+
brilliance_admin/templates/index.html,sha256=B7ExuuNN6qMvD5VHnezrHs_eYlwoLptGSHj96C9Q_EA,1294
|
|
69
|
+
brilliance_admin-0.44.12.dist-info/licenses/LICENSE,sha256=rgWE5Cxk53W0PhTOVmcQedABEWN1QMG-PRz3fz531sE,1074
|
|
70
|
+
brilliance_admin-0.44.12.dist-info/METADATA,sha256=Pt5porK8GT1bv2N3cknxbp31hzXXnarI7r3Dwvy3VVE,7393
|
|
71
|
+
brilliance_admin-0.44.12.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
72
|
+
brilliance_admin-0.44.12.dist-info/top_level.txt,sha256=almFFSWrVYieI3i54hYL0fMUaeuIYiazS2Kx4wtK-ns,17
|
|
73
|
+
brilliance_admin-0.44.12.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Brilliance Admin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
from .category_graphs import CategoryGraphs
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
from typing import Any, Dict, List
|
|
2
|
-
|
|
3
|
-
from pydantic import BaseModel, Field
|
|
4
|
-
|
|
5
|
-
from brilliance_admin.schema import Category
|
|
6
|
-
from brilliance_admin.schema.category import GraphInfoSchemaData
|
|
7
|
-
from brilliance_admin.schema.table.fields_schema import FieldsSchema
|
|
8
|
-
from brilliance_admin.translations import LanguageContext
|
|
9
|
-
from brilliance_admin.utils import SupportsStr
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class GraphData(BaseModel):
|
|
13
|
-
search: str | None = None
|
|
14
|
-
filters: Dict[str, Any] = Field(default_factory=dict)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class ChartData(BaseModel):
|
|
18
|
-
data: dict
|
|
19
|
-
options: dict
|
|
20
|
-
width: int | None = None
|
|
21
|
-
height: int = 50
|
|
22
|
-
type: str = 'line'
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
class GraphsDataResult(BaseModel):
|
|
26
|
-
charts: List[ChartData]
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
class CategoryGraphs(Category):
|
|
30
|
-
_type_slug: str = 'graphs'
|
|
31
|
-
|
|
32
|
-
search_enabled: bool = False
|
|
33
|
-
search_help: SupportsStr | None = None
|
|
34
|
-
|
|
35
|
-
table_filters: FieldsSchema | None = None
|
|
36
|
-
|
|
37
|
-
def generate_schema(self, user, language_context: LanguageContext) -> GraphInfoSchemaData:
|
|
38
|
-
schema = super().generate_schema(user, language_context)
|
|
39
|
-
graph = GraphInfoSchemaData(
|
|
40
|
-
search_enabled=self.search_enabled,
|
|
41
|
-
search_help=language_context.get_text(self.search_help),
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
if self.table_filters:
|
|
45
|
-
graph.table_filters = self.table_filters.generate_schema(user, language_context)
|
|
46
|
-
|
|
47
|
-
schema.graph_info = graph
|
|
48
|
-
return schema
|
|
49
|
-
|
|
50
|
-
async def get_data(self, data: GraphData, user) -> GraphsDataResult:
|
|
51
|
-
raise NotImplementedError('get_data is not implemented')
|
brilliance_admin/schema/group.py
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import abc
|
|
2
|
-
from typing import Dict, List
|
|
3
|
-
|
|
4
|
-
from pydantic.dataclasses import dataclass
|
|
5
|
-
|
|
6
|
-
from brilliance_admin.auth import UserABC
|
|
7
|
-
from brilliance_admin.schema.category import Category, CategorySchemaData
|
|
8
|
-
from brilliance_admin.translations import LanguageContext
|
|
9
|
-
from brilliance_admin.utils import DataclassBase, SupportsStr, get_logger, humanize_field_name
|
|
10
|
-
|
|
11
|
-
logger = get_logger()
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@dataclass
|
|
15
|
-
class GroupSchemaData(DataclassBase):
|
|
16
|
-
title: str | None
|
|
17
|
-
description: str | None
|
|
18
|
-
icon: str | None
|
|
19
|
-
categories: Dict[str, CategorySchemaData]
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
@dataclass
|
|
23
|
-
class Group(abc.ABC):
|
|
24
|
-
categories: List[Category]
|
|
25
|
-
slug: str
|
|
26
|
-
title: SupportsStr | None = None
|
|
27
|
-
description: SupportsStr | None = None
|
|
28
|
-
|
|
29
|
-
# https://pictogrammers.com/library/mdi/
|
|
30
|
-
icon: str | None = None
|
|
31
|
-
|
|
32
|
-
def __post_init__(self):
|
|
33
|
-
for category in self.categories:
|
|
34
|
-
if not issubclass(category.__class__, Category):
|
|
35
|
-
raise TypeError(f'Category "{category}" is not instance of Category subclass')
|
|
36
|
-
|
|
37
|
-
def generate_schema(self, user: UserABC, language_context: LanguageContext) -> GroupSchemaData:
|
|
38
|
-
result = GroupSchemaData(
|
|
39
|
-
title=language_context.get_text(self.title) or humanize_field_name(self.slug),
|
|
40
|
-
description=language_context.get_text(self.description),
|
|
41
|
-
icon=self.icon,
|
|
42
|
-
categories={},
|
|
43
|
-
)
|
|
44
|
-
if not self.categories:
|
|
45
|
-
logger.warning('Group "%s" %s.categories is empty!', self.slug, type(self).__name__)
|
|
46
|
-
|
|
47
|
-
for category in self.categories:
|
|
48
|
-
|
|
49
|
-
if not category.slug:
|
|
50
|
-
msg = f'Category {type(category).__name__}.slug is empty'
|
|
51
|
-
raise AttributeError(msg)
|
|
52
|
-
|
|
53
|
-
if category.slug in result.categories:
|
|
54
|
-
exists = result.categories[category.slug]
|
|
55
|
-
msg = f'Category {type(category).__name__}.slug "{self.slug}" already registered by "{exists.title}"'
|
|
56
|
-
raise KeyError(msg)
|
|
57
|
-
|
|
58
|
-
result.categories[category.slug] = category.generate_schema(user, language_context)
|
|
59
|
-
|
|
60
|
-
return result
|
|
61
|
-
|
|
62
|
-
def get_category(self, category_slug: str) -> Category | None:
|
|
63
|
-
for category in self.categories:
|
|
64
|
-
if category.slug == category_slug:
|
|
65
|
-
return category
|
|
66
|
-
|
|
67
|
-
return None
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
GNU AFFERO GENERAL PUBLIC LICENSE
|
|
2
|
-
Version 3, 19 November 2007
|
|
3
|
-
|
|
4
|
-
Copyright (C) 2025 Your Name
|
|
5
|
-
|
|
6
|
-
This program is free software: you can redistribute it and/or modify
|
|
7
|
-
it under the terms of the GNU Affero General Public License as published
|
|
8
|
-
by the Free Software Foundation, either version 3 of the License, or
|
|
9
|
-
(at your option) any later version.
|
|
10
|
-
|
|
11
|
-
This program is distributed in the hope that it will be useful,
|
|
12
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
-
GNU Affero General Public License for more details.
|
|
15
|
-
|
|
16
|
-
You should have received a copy of the GNU Affero General Public License
|
|
17
|
-
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
File without changes
|