brilliance-admin 0.42.0__py3-none-any.whl → 0.43.7__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.
Files changed (81) hide show
  1. {admin_panel → brilliance_admin}/__init__.py +2 -2
  2. brilliance_admin/api/routers.py +18 -0
  3. {admin_panel → brilliance_admin}/api/utils.py +1 -1
  4. {admin_panel → brilliance_admin}/api/views/auth.py +6 -6
  5. {admin_panel → brilliance_admin}/api/views/autocomplete.py +9 -9
  6. {admin_panel → brilliance_admin}/api/views/graphs.py +8 -8
  7. {admin_panel → brilliance_admin}/api/views/index.py +11 -4
  8. {admin_panel → brilliance_admin}/api/views/schema.py +3 -3
  9. {admin_panel → brilliance_admin}/api/views/settings.py +5 -5
  10. {admin_panel → brilliance_admin}/api/views/table.py +23 -23
  11. {admin_panel → brilliance_admin}/auth.py +1 -1
  12. {admin_panel → brilliance_admin}/exceptions.py +3 -4
  13. {admin_panel → brilliance_admin}/integrations/sqlalchemy/__init__.py +1 -0
  14. {admin_panel → brilliance_admin}/integrations/sqlalchemy/auth.py +6 -6
  15. {admin_panel → brilliance_admin}/integrations/sqlalchemy/autocomplete.py +10 -6
  16. {admin_panel → brilliance_admin}/integrations/sqlalchemy/fields.py +24 -20
  17. {admin_panel → brilliance_admin}/integrations/sqlalchemy/fields_schema.py +27 -18
  18. {admin_panel → brilliance_admin}/integrations/sqlalchemy/table/base.py +8 -8
  19. {admin_panel → brilliance_admin}/integrations/sqlalchemy/table/create.py +10 -10
  20. {admin_panel → brilliance_admin}/integrations/sqlalchemy/table/delete.py +4 -4
  21. {admin_panel → brilliance_admin}/integrations/sqlalchemy/table/list.py +11 -11
  22. {admin_panel → brilliance_admin}/integrations/sqlalchemy/table/retrieve.py +22 -10
  23. {admin_panel → brilliance_admin}/integrations/sqlalchemy/table/update.py +11 -11
  24. brilliance_admin/locales/en.yml +25 -0
  25. brilliance_admin/locales/ru.yml +26 -0
  26. {admin_panel → brilliance_admin}/schema/admin_schema.py +39 -31
  27. {admin_panel → brilliance_admin}/schema/category.py +8 -9
  28. {admin_panel → brilliance_admin}/schema/graphs/category_graphs.py +10 -9
  29. {admin_panel → brilliance_admin}/schema/group.py +10 -10
  30. {admin_panel → brilliance_admin}/schema/table/admin_action.py +8 -7
  31. {admin_panel → brilliance_admin}/schema/table/category_table.py +21 -21
  32. {admin_panel → brilliance_admin}/schema/table/fields/base.py +58 -29
  33. {admin_panel → brilliance_admin}/schema/table/fields/function_field.py +3 -3
  34. {admin_panel → brilliance_admin}/schema/table/fields_schema.py +11 -10
  35. {admin_panel → brilliance_admin}/schema/table/table_models.py +1 -1
  36. admin_panel/static/index-BeniOHDv.js → brilliance_admin/static/index-BnnESruI.js +131 -131
  37. {admin_panel → brilliance_admin}/templates/index.html +1 -1
  38. brilliance_admin/translations.py +115 -0
  39. brilliance_admin/utils.py +153 -0
  40. brilliance_admin-0.43.7.dist-info/METADATA +217 -0
  41. brilliance_admin-0.43.7.dist-info/RECORD +74 -0
  42. brilliance_admin-0.43.7.dist-info/top_level.txt +1 -0
  43. admin_panel/api/routers.py +0 -18
  44. admin_panel/static/favicon.jpg +0 -0
  45. admin_panel/translations.py +0 -145
  46. admin_panel/utils.py +0 -50
  47. brilliance_admin-0.42.0.dist-info/METADATA +0 -155
  48. brilliance_admin-0.42.0.dist-info/RECORD +0 -73
  49. brilliance_admin-0.42.0.dist-info/top_level.txt +0 -1
  50. {admin_panel → brilliance_admin}/api/__init__.py +0 -0
  51. {admin_panel → brilliance_admin}/api/views/__init__.py +0 -0
  52. {admin_panel → brilliance_admin}/docs.py +0 -0
  53. {admin_panel → brilliance_admin}/integrations/__init__.py +0 -0
  54. {admin_panel → brilliance_admin}/integrations/sqlalchemy/table/__init__.py +0 -0
  55. {admin_panel → brilliance_admin}/schema/__init__.py +0 -0
  56. {admin_panel → brilliance_admin}/schema/graphs/__init__.py +0 -0
  57. {admin_panel → brilliance_admin}/schema/table/__init__.py +0 -0
  58. {admin_panel → brilliance_admin}/schema/table/fields/__init__.py +0 -0
  59. {admin_panel → brilliance_admin}/static/index-vlBToOhT.css +0 -0
  60. {admin_panel → brilliance_admin}/static/materialdesignicons-webfont-CYDMK1kx.woff2 +0 -0
  61. {admin_panel → brilliance_admin}/static/materialdesignicons-webfont-CgCzGbLl.woff +0 -0
  62. {admin_panel → brilliance_admin}/static/materialdesignicons-webfont-D3kAzl71.ttf +0 -0
  63. {admin_panel → brilliance_admin}/static/materialdesignicons-webfont-DttUABo4.eot +0 -0
  64. {admin_panel → brilliance_admin}/static/tinymce/dark-first/content.min.css +0 -0
  65. {admin_panel → brilliance_admin}/static/tinymce/dark-first/skin.min.css +0 -0
  66. {admin_panel → brilliance_admin}/static/tinymce/dark-slim/content.min.css +0 -0
  67. {admin_panel → brilliance_admin}/static/tinymce/dark-slim/skin.min.css +0 -0
  68. {admin_panel → brilliance_admin}/static/tinymce/img/example.png +0 -0
  69. {admin_panel → brilliance_admin}/static/tinymce/img/tinymce.woff2 +0 -0
  70. {admin_panel → brilliance_admin}/static/tinymce/lightgray/content.min.css +0 -0
  71. {admin_panel → brilliance_admin}/static/tinymce/lightgray/fonts/tinymce.woff +0 -0
  72. {admin_panel → brilliance_admin}/static/tinymce/lightgray/skin.min.css +0 -0
  73. {admin_panel → brilliance_admin}/static/tinymce/plugins/accordion/css/accordion.css +0 -0
  74. {admin_panel → brilliance_admin}/static/tinymce/plugins/accordion/plugin.js +0 -0
  75. {admin_panel → brilliance_admin}/static/tinymce/plugins/codesample/css/prism.css +0 -0
  76. {admin_panel → brilliance_admin}/static/tinymce/plugins/customLink/css/link.css +0 -0
  77. {admin_panel → brilliance_admin}/static/tinymce/plugins/customLink/plugin.js +0 -0
  78. {admin_panel → brilliance_admin}/static/tinymce/tinymce.min.js +0 -0
  79. {admin_panel → brilliance_admin}/static/vanilla-picker-B6E6ObS_.js +0 -0
  80. {brilliance_admin-0.42.0.dist-info → brilliance_admin-0.43.7.dist-info}/WHEEL +0 -0
  81. {brilliance_admin-0.42.0.dist-info → brilliance_admin-0.43.7.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,9 @@
1
- from admin_panel import schema
2
- from admin_panel.auth import UserABC
3
- from admin_panel.exceptions import AdminAPIException, APIError
4
- from admin_panel.translations import LanguageManager
5
- from admin_panel.translations import TranslateText as _
6
- from admin_panel.utils import get_logger
1
+ from brilliance_admin import schema
2
+ from brilliance_admin.auth import UserABC
3
+ from brilliance_admin.exceptions import AdminAPIException, APIError
4
+ from brilliance_admin.translations import LanguageContext
5
+ from brilliance_admin.translations import TranslateText as _
6
+ from brilliance_admin.utils import get_logger
7
7
 
8
8
  logger = get_logger()
9
9
 
@@ -15,10 +15,10 @@ class SQLAlchemyAdminCreate:
15
15
  self,
16
16
  data: dict,
17
17
  user: UserABC,
18
- language_manager: LanguageManager,
18
+ language_context: LanguageContext,
19
19
  ) -> schema.CreateResult:
20
20
  if not self.has_create:
21
- raise AdminAPIException(APIError(message=_('method_not_allowed')), status_code=500)
21
+ raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
22
22
 
23
23
  # pylint: disable=import-outside-toplevel
24
24
  from sqlalchemy.exc import IntegrityError
@@ -37,7 +37,7 @@ class SQLAlchemyAdminCreate:
37
37
  type(self).__name__, self.table_schema.model.__name__, e,
38
38
  extra={'data': data},
39
39
  )
40
- msg = _('connection_refused_error') % {'error': str(e)}
40
+ msg = _('errors.connection_refused_error') % {'error': str(e)}
41
41
  raise AdminAPIException(
42
42
  APIError(message=msg, code='connection_refused_error'),
43
43
  status_code=500,
@@ -62,7 +62,7 @@ class SQLAlchemyAdminCreate:
62
62
  extra={'data': data},
63
63
  )
64
64
  raise AdminAPIException(
65
- APIError(message=_('db_error_create'), code='db_error_create'), status_code=500,
65
+ APIError(message=_('errors.db_error_create'), code='db_error_create'), status_code=500,
66
66
  ) from e
67
67
 
68
68
  logger.info(
@@ -1,6 +1,6 @@
1
- from admin_panel.exceptions import APIError, AdminAPIException
2
- from admin_panel.schema.table.admin_action import ActionData, ActionMessage, ActionResult, admin_action
3
- from admin_panel.translations import TranslateText as _
1
+ from brilliance_admin.exceptions import APIError, AdminAPIException
2
+ from brilliance_admin.schema.table.admin_action import ActionData, ActionMessage, ActionResult, admin_action
3
+ from brilliance_admin.translations import TranslateText as _
4
4
 
5
5
 
6
6
  class SQLAlchemyDeleteAction:
@@ -14,5 +14,5 @@ class SQLAlchemyDeleteAction:
14
14
  )
15
15
  async def delete(self, action_data: ActionData):
16
16
  if not self.has_delete:
17
- raise AdminAPIException(APIError(message=_('method_not_allowed')), status_code=500)
17
+ raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
18
18
  return ActionResult(message=ActionMessage(_('deleted_successfully')))
@@ -1,9 +1,9 @@
1
- from admin_panel import auth, schema
2
- from admin_panel.exceptions import AdminAPIException, APIError, FieldError
3
- from admin_panel.integrations.sqlalchemy.fields_schema import SQLAlchemyFieldsSchema
4
- from admin_panel.translations import LanguageManager
5
- from admin_panel.translations import TranslateText as _
6
- from admin_panel.utils import get_logger
1
+ from brilliance_admin import auth, schema
2
+ from brilliance_admin.exceptions import AdminAPIException, APIError, FieldError
3
+ from brilliance_admin.integrations.sqlalchemy.fields_schema import SQLAlchemyFieldsSchema
4
+ from brilliance_admin.translations import LanguageContext
5
+ from brilliance_admin.translations import TranslateText as _
6
+ from brilliance_admin.utils import get_logger
7
7
 
8
8
  logger = get_logger()
9
9
 
@@ -87,7 +87,7 @@ class SQLAlchemyAdminListMixin:
87
87
  self,
88
88
  list_data: schema.ListData,
89
89
  user: auth.UserABC,
90
- language_manager: LanguageManager,
90
+ language_context: LanguageContext,
91
91
  ) -> schema.TableListResult:
92
92
  # pylint: disable=import-outside-toplevel
93
93
  from sqlalchemy import exc, func, select
@@ -109,7 +109,7 @@ class SQLAlchemyAdminListMixin:
109
109
  'list_data': list_data,
110
110
  }
111
111
  )
112
- msg = _('filter_error') % {'error': e.message}
112
+ msg = _('errors.filter_error') % {'error': e.message}
113
113
  raise AdminAPIException(APIError(message=msg, code='filters_exception'), status_code=500) from e
114
114
 
115
115
  except Exception as e:
@@ -120,7 +120,7 @@ class SQLAlchemyAdminListMixin:
120
120
  'list_data': list_data,
121
121
  }
122
122
  )
123
- raise AdminAPIException(APIError(message=_('filters_exception'), code='filters_exception'), status_code=500) from e
123
+ raise AdminAPIException(APIError(message=_('errors.filters_exception'), code='filters_exception'), status_code=500) from e
124
124
 
125
125
  data = []
126
126
 
@@ -143,7 +143,7 @@ class SQLAlchemyAdminListMixin:
143
143
  'list_data': list_data,
144
144
  }
145
145
  )
146
- msg = _('connection_refused_error') % {'error': str(e)}
146
+ msg = _('errors.connection_refused_error') % {'error': str(e)}
147
147
  raise AdminAPIException(
148
148
  APIError(message=msg, code='connection_refused_error'),
149
149
  status_code=500,
@@ -172,7 +172,7 @@ class SQLAlchemyAdminListMixin:
172
172
  }
173
173
  )
174
174
  raise AdminAPIException(
175
- APIError(message=_('db_error_list'), code='db_error_list'), status_code=500,
175
+ APIError(message=_('errors.db_error_list'), code='db_error_list'), status_code=500,
176
176
  ) from e
177
177
 
178
178
  return schema.TableListResult(data=data, total_count=int(total_count or 0))
@@ -1,10 +1,11 @@
1
1
  from typing import Any
2
2
 
3
- from admin_panel import auth, schema
4
- from admin_panel.exceptions import AdminAPIException, APIError
5
- from admin_panel.translations import LanguageManager
6
- from admin_panel.translations import TranslateText as _
7
- from admin_panel.utils import get_logger
3
+ from brilliance_admin import auth, schema
4
+ from brilliance_admin.exceptions import AdminAPIException, APIError, FieldError
5
+ from brilliance_admin.integrations.sqlalchemy.fields_schema import SQLAlchemyFieldsSchema
6
+ from brilliance_admin.translations import LanguageContext
7
+ from brilliance_admin.translations import TranslateText as _
8
+ from brilliance_admin.utils import get_logger
8
9
 
9
10
  logger = get_logger()
10
11
 
@@ -12,14 +13,16 @@ logger = get_logger()
12
13
  class SQLAlchemyAdminRetrieveMixin:
13
14
  has_retrieve: bool = True
14
15
 
16
+ table_schema: SQLAlchemyFieldsSchema
17
+
15
18
  async def retrieve(
16
19
  self,
17
20
  pk: Any,
18
21
  user: auth.UserABC,
19
- language_manager: LanguageManager,
22
+ language_context: LanguageContext,
20
23
  ) -> schema.RetrieveResult:
21
24
  if not self.has_delete:
22
- raise AdminAPIException(APIError(message=_('method_not_allowed')), status_code=500)
25
+ raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
23
26
 
24
27
  # pylint: disable=import-outside-toplevel
25
28
  from sqlalchemy import inspect
@@ -38,16 +41,25 @@ class SQLAlchemyAdminRetrieveMixin:
38
41
  extra={"record": record, "user": user},
39
42
  )
40
43
 
44
+ except FieldError as e:
45
+ logger.exception(
46
+ 'SQLAlchemy %s retrieve %s #%s field error: %s',
47
+ type(self).__name__, self.model.__name__, pk, e,
48
+ )
49
+ msg = _('errors.serialize_field_error') % {'error': e.message}
50
+ raise AdminAPIException(APIError(message=msg, code='filters_exception'), status_code=500) from e
51
+
41
52
  except Exception as e:
42
53
  logger.exception(
43
- 'SQLAlchemy %s retrieve db error: %s', type(self).__name__, e,
54
+ 'SQLAlchemy %s retrieve %s #%s db error: %s',
55
+ type(self).__name__, self.model.__name__, pk, e,
44
56
  )
45
57
  raise AdminAPIException(
46
- APIError(message=_('db_error_retrieve'), code='db_error_retrieve'), status_code=500,
58
+ APIError(message=_('errors.db_error_retrieve'), code='db_error_retrieve'), status_code=500,
47
59
  ) from e
48
60
 
49
61
  if record is None:
50
- msg = _('record_not_found') % {'pk_name': self.pk_name, 'pk': pk}
62
+ msg = _('errors.record_not_found') % {'pk_name': self.pk_name, 'pk': pk}
51
63
  raise AdminAPIException(
52
64
  APIError(message=msg, code='record_not_found'),
53
65
  status_code=400,
@@ -1,10 +1,10 @@
1
1
  from typing import Any
2
2
 
3
- from admin_panel import auth, schema
4
- from admin_panel.exceptions import AdminAPIException, APIError
5
- from admin_panel.translations import LanguageManager
6
- from admin_panel.translations import TranslateText as _
7
- from admin_panel.utils import get_logger
3
+ from brilliance_admin import auth, schema
4
+ from brilliance_admin.exceptions import AdminAPIException, APIError
5
+ from brilliance_admin.translations import LanguageContext
6
+ from brilliance_admin.translations import TranslateText as _
7
+ from brilliance_admin.utils import get_logger
8
8
 
9
9
  logger = get_logger()
10
10
 
@@ -18,10 +18,10 @@ class SQLAlchemyAdminUpdate:
18
18
  pk: Any,
19
19
  data: dict,
20
20
  user: auth.UserABC,
21
- language_manager: LanguageManager,
21
+ language_context: LanguageContext,
22
22
  ) -> schema.UpdateResult:
23
23
  if not self.has_update:
24
- raise AdminAPIException(APIError(message=_('method_not_allowed')), status_code=500)
24
+ raise AdminAPIException(APIError(message=_('errors.method_not_allowed')), status_code=500)
25
25
 
26
26
  # pylint: disable=import-outside-toplevel
27
27
  from sqlalchemy import inspect
@@ -29,7 +29,7 @@ class SQLAlchemyAdminUpdate:
29
29
 
30
30
  if pk is None:
31
31
  raise AdminAPIException(
32
- APIError(message=_('pk_not_found') % {'pk_name': self.pk_name}, code='pk_not_found'),
32
+ APIError(message=_('errors.pk_not_found') % {'pk_name': self.pk_name}, code='pk_not_found'),
33
33
  status_code=400,
34
34
  )
35
35
 
@@ -42,7 +42,7 @@ class SQLAlchemyAdminUpdate:
42
42
  async with self.db_async_session() as session:
43
43
  record = (await session.execute(stmt)).scalars().first()
44
44
  if record is None:
45
- msg = _('record_not_found') % {'pk_name': self.pk_name, 'pk': pk}
45
+ msg = _('errors.record_not_found') % {'pk_name': self.pk_name, 'pk': pk}
46
46
  raise AdminAPIException(
47
47
  APIError(message=msg, code='record_not_found'),
48
48
  status_code=400,
@@ -59,7 +59,7 @@ class SQLAlchemyAdminUpdate:
59
59
  type(self).__name__, self.table_schema.model.__name__, pk, e,
60
60
  extra={'data': data},
61
61
  )
62
- msg = _('connection_refused_error') % {'error': str(e)}
62
+ msg = _('errors.connection_refused_error') % {'error': str(e)}
63
63
  raise AdminAPIException(
64
64
  APIError(message=msg, code='connection_refused_error'),
65
65
  status_code=400,
@@ -84,7 +84,7 @@ class SQLAlchemyAdminUpdate:
84
84
  extra={'data': data}
85
85
  )
86
86
  raise AdminAPIException(
87
- APIError(message=_('db_error_update'), code='db_error_update'), status_code=500,
87
+ APIError(message=_('errors.db_error_update'), code='db_error_update'), status_code=500,
88
88
  ) from e
89
89
 
90
90
  logger.info(
@@ -0,0 +1,25 @@
1
+ delete: 'Delete'
2
+ delete_confirmation_text: "Are you sure you want to delete those records?\nThis action cannot be undone."
3
+ deleted_successfully: 'The entries were successfully deleted.'
4
+
5
+ errors:
6
+ db_error_create: 'Error creating a record in the database.'
7
+ db_error_update: 'Error updating the record in the database.'
8
+ db_error_retrieve: 'Error retrieving the record from the database.'
9
+ db_error_list: 'Failed to retrieve table data from the database.'
10
+ pk_not_found: 'The "%(pk_name)s" field was not found in the submitted data.'
11
+ record_not_found: 'No record found for %(pk_name)s=%(pk)s.'
12
+ connection_refused_error: 'Database connection error: %(error)s'
13
+ filters_exception: 'An unknown technical error occurred while filtering data.'
14
+ method_not_allowed: 'Error, method not allowed. This action is not permitted.'
15
+ filter_error: 'An error occurred during filtering: {error}'
16
+
17
+ search_help: 'Available search fields: %(fields)s'
18
+ sqlalchemy_search_help: |
19
+ <b>Available search fields:</b>
20
+ %(fields)s
21
+
22
+ <b>Available operators:</b>
23
+ <b>""</b> - quotes for exact match
24
+ <b>%%</b> - any sequence of characters
25
+ <b>_</b> - any single character
@@ -0,0 +1,26 @@
1
+ delete: 'Удалить'
2
+ delete_confirmation_text: "Вы уверены, что хотите удалить данные записи?\nДанное действие нельзя отменить."
3
+ deleted_successfully: 'Записи успешно удалены.'
4
+
5
+ errors:
6
+ pk_not_found: 'Поле "%(pk_name)s" не найдено среди переданных данных.'
7
+ record_not_found: 'Запись по ключу %(pk_name)s=%(pk)s не найдена.'
8
+ db_error_create: 'Ошибка создания записи в базе данных.'
9
+ db_error_update: 'Ошибка обновления записи в базе данных.'
10
+ db_error_retrieve: 'Ошибка получения записи из базы данных.'
11
+ db_error_list: 'Ошибка получения данных таблицы из базы данных.'
12
+ connection_refused_error: 'Ошибка подключения к базе данных: %(error)s'
13
+ filters_exception: 'Произошла неизвестная техническая ошибка при фильтрации данных.'
14
+ method_not_allowed: 'Ошибка, данный метод недоступен.'
15
+ filter_error: 'Проишла ошибка при фильтрации: %(error)s'
16
+ serialize_field_error: 'Ошибка чтения данных: %(error)s'
17
+
18
+ search_help: 'Доступные поля для поиска: %(fields)s'
19
+ sqlalchemy_search_help: |
20
+ <b>Доступные поля для поиска:</b>
21
+ %(fields)s
22
+
23
+ <b>Доступные операторы:</b>
24
+ <b>""</b> - кавычки для точного совпадения
25
+ <b>%%</b> - любая последовательность символов
26
+ <b>_</b> - один любой символ
@@ -1,7 +1,7 @@
1
1
  import importlib.metadata
2
2
  import json
3
3
  from importlib import resources
4
- from typing import Any, Dict, List, Optional, Type
4
+ from typing import Any, Dict, List, Optional
5
5
  from urllib.parse import urljoin
6
6
 
7
7
  from fastapi import FastAPI, Request
@@ -9,11 +9,16 @@ from fastapi.middleware.cors import CORSMiddleware
9
9
  from fastapi.staticfiles import StaticFiles
10
10
  from pydantic.dataclasses import dataclass
11
11
 
12
- from admin_panel.auth import UserABC
13
- from admin_panel.docs import build_redoc_docs, build_scalar_docs
14
- from admin_panel.schema.group import Group, GroupSchemaData
15
- from admin_panel.translations import LanguageManager, TranslateText
16
- from admin_panel.utils import DataclassBase
12
+ from brilliance_admin.auth import UserABC
13
+ from brilliance_admin.docs import build_redoc_docs, build_scalar_docs
14
+ from brilliance_admin.schema.group import Group, GroupSchemaData
15
+ from brilliance_admin.translations import LanguageContext, LanguageManager
16
+ from brilliance_admin.utils import DataclassBase, SupportsStr
17
+
18
+ DEFAULT_LANGUAGES = {
19
+ 'ru': 'Russian',
20
+ 'en': 'English',
21
+ }
17
22
 
18
23
 
19
24
  @dataclass
@@ -29,9 +34,9 @@ class AdminSchemaData(DataclassBase):
29
34
  # pylint: disable=too-many-instance-attributes
30
35
  @dataclass
31
36
  class AdminSettingsData(DataclassBase):
32
- title: str | TranslateText
33
- description: str | TranslateText | None
34
- login_greetings_message: str | TranslateText | None
37
+ title: SupportsStr
38
+ description: SupportsStr | None
39
+ login_greetings_message: SupportsStr | None
35
40
  navbar_density: str
36
41
  languages: Dict[str, str] | None
37
42
 
@@ -39,7 +44,7 @@ class AdminSettingsData(DataclassBase):
39
44
  @dataclass
40
45
  class AdminIndexContextData(DataclassBase):
41
46
  title: str
42
- favicon_image: str
47
+ favicon_image: str | None
43
48
  settings_json: str
44
49
 
45
50
 
@@ -48,30 +53,33 @@ class AdminSchema:
48
53
  groups: List[Group]
49
54
  auth: Any
50
55
 
51
- title: str | TranslateText | None = 'Admin'
52
- description: str | TranslateText | None = None
53
- login_greetings_message: str | TranslateText | None = None
56
+ title: SupportsStr | None = 'Admin'
57
+ description: SupportsStr | None = None
58
+ login_greetings_message: SupportsStr | None = None
54
59
 
55
60
  logo_image: str | None = None
56
- favicon_image: str = '/admin/static/favicon.jpg'
61
+ favicon_image: str | None = None
57
62
 
58
63
  navbar_density: str = 'default'
59
64
 
60
65
  backend_prefix = None
61
66
  static_prefix = None
62
67
 
63
- language_manager_class: Type[LanguageManager] = LanguageManager
68
+ language_manager: LanguageManager | None = None
64
69
 
65
70
  def __post_init__(self):
66
71
  for group in self.groups:
67
72
  if not issubclass(group.__class__, Group):
68
73
  raise TypeError(f'Group "{group}" is not instance of Group subclass')
69
74
 
70
- def get_language_manager(self, language_slug: str | None) -> LanguageManager:
71
- return self.language_manager_class(language_slug)
75
+ if not self.language_manager:
76
+ self.language_manager = LanguageManager(DEFAULT_LANGUAGES)
77
+
78
+ def get_language_context(self, language_slug: str | None) -> LanguageContext:
79
+ return LanguageContext(language_slug, language_manager=self.language_manager)
72
80
 
73
81
  def generate_schema(self, user: UserABC, language_slug: str | None) -> AdminSchemaData:
74
- language_manager: LanguageManager = self.get_language_manager(language_slug)
82
+ language_context: LanguageContext = self.get_language_context(language_slug)
75
83
 
76
84
  groups = {}
77
85
 
@@ -80,7 +88,7 @@ class AdminSchema:
80
88
  msg = f'Category group {type(group).__name__}.slug is empty'
81
89
  raise AttributeError(msg)
82
90
 
83
- groups[group.slug] = group.generate_schema(user, language_manager)
91
+ groups[group.slug] = group.generate_schema(user, language_context)
84
92
 
85
93
  return AdminSchemaData(
86
94
  groups=groups,
@@ -96,13 +104,13 @@ class AdminSchema:
96
104
 
97
105
  async def get_settings(self, request: Request) -> AdminSettingsData:
98
106
  language_slug = request.headers.get('Accept-Language')
99
- language_manager: LanguageManager = self.get_language_manager(language_slug)
107
+ language_context: LanguageContext = self.get_language_context(language_slug)
100
108
 
101
109
  languages = None
102
- if language_manager.languages:
110
+ if self.language_manager.languages:
103
111
  languages = {}
104
- for k, v in language_manager.languages.items():
105
- languages[k] = language_manager.get_text(v)
112
+ for k, v in self.language_manager.languages.items():
113
+ languages[k] = v
106
114
 
107
115
  return AdminSettingsData(
108
116
  title=self.title,
@@ -124,11 +132,11 @@ class AdminSchema:
124
132
  include_redoc=False,
125
133
  ) -> FastAPI:
126
134
  # pylint: disable=unused-variable
127
- language_manager = self.get_language_manager(language_slug=None)
135
+ language_context = self.get_language_context(language_slug=None)
128
136
 
129
137
  app = FastAPI(
130
- title=language_manager.get_text(self.title),
131
- description=language_manager.get_text(self.description),
138
+ title=language_context.get_text(self.title),
139
+ description=language_context.get_text(self.description),
132
140
  debug=debug,
133
141
  docs_url='/docs' if include_docs else None,
134
142
  redoc_url=None,
@@ -143,7 +151,7 @@ class AdminSchema:
143
151
  allow_headers=["*"]
144
152
  )
145
153
 
146
- static_dir = resources.files("admin_panel").joinpath("static")
154
+ static_dir = resources.files("brilliance_admin").joinpath("static")
147
155
  app.mount("/static", StaticFiles(directory=str(static_dir)), name="static")
148
156
 
149
157
  app.state.schema = self
@@ -155,14 +163,14 @@ class AdminSchema:
155
163
  app.include_router(build_redoc_docs(app, redoc_url='/redoc'))
156
164
 
157
165
  # pylint: disable=import-outside-toplevel
158
- from admin_panel.api.routers import admin_panel_router
159
- app.include_router(admin_panel_router)
166
+ from brilliance_admin.api.routers import brilliance_admin_router
167
+ app.include_router(brilliance_admin_router)
160
168
 
161
169
  return app
162
170
 
163
171
  async def get_index_context_data(self, request: Request) -> dict:
164
- language_manager = self.get_language_manager(language_slug=None)
165
- context = {'language_manager': language_manager}
172
+ language_context = self.get_language_context(language_slug=None)
173
+ context = {'language_context': language_context}
166
174
 
167
175
  backend_prefix = self.backend_prefix
168
176
  if not backend_prefix:
@@ -5,9 +5,9 @@ from pydantic import Field
5
5
  from pydantic.dataclasses import dataclass
6
6
  from pydantic_core import core_schema
7
7
 
8
- from admin_panel.auth import UserABC
9
- from admin_panel.translations import LanguageManager, TranslateText
10
- from admin_panel.utils import DataclassBase
8
+ from brilliance_admin.auth import UserABC
9
+ from brilliance_admin.translations import LanguageContext
10
+ from brilliance_admin.utils import DataclassBase, SupportsStr, humanize_field_name
11
11
 
12
12
 
13
13
  # pylint: disable=too-many-instance-attributes
@@ -30,7 +30,6 @@ class FieldSchemaData(DataclassBase):
30
30
 
31
31
  choices: List[dict] | None = None
32
32
 
33
- tag_colors: dict | None = None
34
33
  variant: str | None = None
35
34
  size: str | None = None
36
35
 
@@ -116,18 +115,18 @@ class CategorySchemaData(DataclassBase):
116
115
 
117
116
  class Category(abc.ABC):
118
117
  slug: ClassVar[str]
119
- title: ClassVar[str | TranslateText | None] = None
120
- description: ClassVar[str | TranslateText | None] = None
118
+ title: ClassVar[SupportsStr | None] = None
119
+ description: ClassVar[SupportsStr | None] = None
121
120
 
122
121
  # https://pictogrammers.com/library/mdi/
123
122
  icon: ClassVar[str | None] = None
124
123
 
125
124
  _type_slug: ClassVar[str]
126
125
 
127
- def generate_schema(self, user: UserABC, language_manager: LanguageManager) -> CategorySchemaData:
126
+ def generate_schema(self, user: UserABC, language_context: LanguageContext) -> CategorySchemaData:
128
127
  return CategorySchemaData(
129
- title=language_manager.get_text(self.title) or self.slug,
130
- description=language_manager.get_text(self.description),
128
+ title=language_context.get_text(self.title) or humanize_field_name(self.slug),
129
+ description=language_context.get_text(self.description),
131
130
  icon=self.icon,
132
131
  type=self._type_slug,
133
132
  )
@@ -2,10 +2,11 @@ from typing import Any, Dict, List
2
2
 
3
3
  from pydantic import BaseModel, Field
4
4
 
5
- from admin_panel.schema import Category
6
- from admin_panel.schema.category import GraphInfoSchemaData
7
- from admin_panel.schema.table.fields_schema import FieldsSchema
8
- from admin_panel.translations import LanguageManager, TranslateText
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
9
10
 
10
11
 
11
12
  class GraphData(BaseModel):
@@ -29,19 +30,19 @@ class CategoryGraphs(Category):
29
30
  _type_slug: str = 'graphs'
30
31
 
31
32
  search_enabled: bool = False
32
- search_help: str | TranslateText | None = None
33
+ search_help: SupportsStr | None = None
33
34
 
34
35
  table_filters: FieldsSchema | None = None
35
36
 
36
- def generate_schema(self, user, language_manager: LanguageManager) -> GraphInfoSchemaData:
37
- schema = super().generate_schema(user, language_manager)
37
+ def generate_schema(self, user, language_context: LanguageContext) -> GraphInfoSchemaData:
38
+ schema = super().generate_schema(user, language_context)
38
39
  graph = GraphInfoSchemaData(
39
40
  search_enabled=self.search_enabled,
40
- search_help=language_manager.get_text(self.search_help),
41
+ search_help=language_context.get_text(self.search_help),
41
42
  )
42
43
 
43
44
  if self.table_filters:
44
- graph.table_filters = self.table_filters.generate_schema(user, language_manager)
45
+ graph.table_filters = self.table_filters.generate_schema(user, language_context)
45
46
 
46
47
  schema.graph_info = graph
47
48
  return schema
@@ -3,10 +3,10 @@ from typing import Dict, List
3
3
 
4
4
  from pydantic.dataclasses import dataclass
5
5
 
6
- from admin_panel.auth import UserABC
7
- from admin_panel.schema.category import Category, CategorySchemaData
8
- from admin_panel.translations import LanguageManager, TranslateText
9
- from admin_panel.utils import DataclassBase, get_logger
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
10
 
11
11
  logger = get_logger()
12
12
 
@@ -23,8 +23,8 @@ class GroupSchemaData(DataclassBase):
23
23
  class Group(abc.ABC):
24
24
  categories: List[Category]
25
25
  slug: str
26
- title: str | TranslateText | None = None
27
- description: str | TranslateText | None = None
26
+ title: SupportsStr | None = None
27
+ description: SupportsStr | None = None
28
28
 
29
29
  # https://pictogrammers.com/library/mdi/
30
30
  icon: str | None = None
@@ -34,10 +34,10 @@ class Group(abc.ABC):
34
34
  if not issubclass(category.__class__, Category):
35
35
  raise TypeError(f'Category "{category}" is not instance of Category subclass')
36
36
 
37
- def generate_schema(self, user: UserABC, language_manager: LanguageManager) -> GroupSchemaData:
37
+ def generate_schema(self, user: UserABC, language_context: LanguageContext) -> GroupSchemaData:
38
38
  result = GroupSchemaData(
39
- title=language_manager.get_text(self.title) or self.slug,
40
- description=language_manager.get_text(self.description),
39
+ title=language_context.get_text(self.title) or humanize_field_name(self.slug),
40
+ description=language_context.get_text(self.description),
41
41
  icon=self.icon,
42
42
  categories={},
43
43
  )
@@ -55,7 +55,7 @@ class Group(abc.ABC):
55
55
  msg = f'Category {type(category).__name__}.slug "{self.slug}" already registered by "{exists.title}"'
56
56
  raise KeyError(msg)
57
57
 
58
- result.categories[category.slug] = category.generate_schema(user, language_manager)
58
+ result.categories[category.slug] = category.generate_schema(user, language_context)
59
59
 
60
60
  return result
61
61
 
@@ -4,8 +4,9 @@ from typing import Any, Dict, List, Optional
4
4
  from pydantic import BaseModel, Field, validate_call
5
5
  from pydantic.dataclasses import dataclass
6
6
 
7
- from admin_panel.schema.table.fields_schema import FieldsSchema
8
- from admin_panel.translations import DataclassBase, TranslateText
7
+ from brilliance_admin.schema.table.fields_schema import FieldsSchema
8
+ from brilliance_admin.translations import DataclassBase
9
+ from brilliance_admin.utils import SupportsStr
9
10
 
10
11
 
11
12
  class ActionData(BaseModel):
@@ -20,7 +21,7 @@ class ActionData(BaseModel):
20
21
 
21
22
  @dataclass
22
23
  class ActionMessage(DataclassBase):
23
- text: str | TranslateText
24
+ text: SupportsStr
24
25
  type: str = 'success'
25
26
  position: str = 'top-center'
26
27
 
@@ -28,16 +29,16 @@ class ActionMessage(DataclassBase):
28
29
  @dataclass
29
30
  class ActionResult(DataclassBase):
30
31
  message: ActionMessage | None = None
31
- persistent_message: str | TranslateText | None = None
32
+ persistent_message: SupportsStr | None = None
32
33
 
33
34
 
34
35
  # pylint: disable=too-many-arguments
35
36
  # pylint: disable=too-many-positional-arguments
36
37
  @validate_call
37
38
  def admin_action(
38
- title: str | TranslateText,
39
- description: Optional[str | TranslateText] = None,
40
- confirmation_text: Optional[str | TranslateText] = None,
39
+ title: SupportsStr,
40
+ description: Optional[SupportsStr] = None,
41
+ confirmation_text: Optional[SupportsStr] = None,
41
42
 
42
43
  # https://vuetifyjs.com/en/styles/colors/#material-colors
43
44
  base_color: Optional[str] = None,