accrete 0.0.54__py3-none-any.whl → 0.0.56__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.
@@ -13,7 +13,8 @@ from .context import (
13
13
  extract_url_params,
14
14
  exclude_params,
15
15
  url_param_str,
16
- get_table_fields
16
+ get_table_fields,
17
+ default_table_context
17
18
  )
18
19
  from .elements import (
19
20
  ClientActionGroup,
@@ -1,12 +1,13 @@
1
1
  import logging
2
+ import json
2
3
  from urllib.parse import quote_plus
3
4
  from dataclasses import dataclass, field
4
- from typing import TypedDict, Callable
5
+ from typing import Type, TypedDict, Callable
5
6
  from django.utils.translation import gettext_lazy as _t
6
7
  from django.db import models
7
8
  from django.db.models import Model, QuerySet
8
9
  from django.core.paginator import Paginator
9
- from django.core import paginator
10
+ from django.core import paginator, exceptions
10
11
  from django.forms import Form, ModelForm
11
12
  from accrete.annotation import Annotation
12
13
  from .elements import (
@@ -14,7 +15,7 @@ from .elements import (
14
15
  ClientActionGroup
15
16
  )
16
17
  from .filter import Filter
17
-
18
+ from accrete.utils import filter_from_querystring
18
19
 
19
20
  _logger = logging.getLogger(__name__)
20
21
 
@@ -60,6 +61,46 @@ class TableContext(Context):
60
61
  field_selection: bool = True
61
62
 
62
63
 
64
+ def default_table_context(model: Type[Model], params: dict, queryset=None, **kwargs) -> TableContext:
65
+ if queryset is None:
66
+ queryset = filter_from_querystring(model, params)
67
+ page = list_page(
68
+ queryset,
69
+ cast_param(params, 'paginate_by', int, 40),
70
+ cast_param(params, 'page', int, 1)
71
+ )
72
+ try:
73
+ has_name_field = (
74
+ model._meta.get_field('name').get_internal_type() == 'CharField'
75
+ )
76
+ except exceptions.FieldDoesNotExist:
77
+ has_name_field = False
78
+
79
+ ctx = TableContext(
80
+ title=str(model._meta.verbose_name_plural),
81
+ object_label=str(model._meta.verbose_name),
82
+ object_param_str=url_param_str(
83
+ params,
84
+ ['q', 'paginate_by', 'page', 'fields']
85
+ ),
86
+ fields=get_table_fields(
87
+ cast_param(params, 'fields', json.loads, []), model
88
+ ),
89
+ list_page=page,
90
+ pagination_param_str=url_param_str(
91
+ params, ['q', 'paginate_by', 'fields']
92
+ ),
93
+ endless_scroll=True,
94
+ filter=Filter(
95
+ model,
96
+ default_filter_term='name__icontains' if has_name_field else ''
97
+ ),
98
+ kwargs=kwargs
99
+ )
100
+ return ctx
101
+
102
+
103
+
63
104
  @dataclass
64
105
  class ListContext(Context):
65
106
 
@@ -67,7 +108,7 @@ class ListContext(Context):
67
108
  object_param_str: str
68
109
  list_page: paginator.Page
69
110
  pagination_param_str: str
70
- filter: Filter
111
+ filter: Filter = None
71
112
  endless_scroll: bool = True
72
113
  column_height: int = 4
73
114
  column_width: int = 12
@@ -93,7 +134,9 @@ class DetailContext(Context):
93
134
  class FormContext(Context):
94
135
 
95
136
  form: Form | ModelForm
96
- form_id: str
137
+ form_id: str = 'form'
138
+ form_method: str = 'post'
139
+ form_action: str = ''
97
140
 
98
141
 
99
142
  def cast_param(params: dict, param: str, cast_to: Callable, default):
@@ -115,9 +158,8 @@ def url_param_dict(get_params: dict) -> dict:
115
158
 
116
159
  def url_param_str(params: dict, extract: list[str] = None) -> str:
117
160
  """
118
- Return a URL Querystring from the given parameters
119
- If extract is supplied, extract the value from the dictionary and prepare
120
- them, so that each value is formatted e.g. {'page': '&page=1'}
161
+ Return a URL Querystring from the given params dict.
162
+ If extract is supplied, only specified keys will be used.
121
163
  """
122
164
  if extract:
123
165
  params = extract_url_params(params, extract)
@@ -25,15 +25,6 @@ class ActionMethod(Enum):
25
25
  DELETE = 'hx-delete'
26
26
 
27
27
 
28
- @dataclass
29
- class ClientActionGroup:
30
-
31
- name: str
32
- actions: list[ActionMethod] = field(default_factory=list)
33
- icon: Icon | type[Enum] = None
34
- icon_only: bool = False
35
-
36
-
37
28
  @dataclass
38
29
  class ClientAction:
39
30
 
@@ -51,6 +42,15 @@ class ClientAction:
51
42
  return ' '.join([f'{str(attr[0])}={str(attr[1])}' for attr in self.attrs])
52
43
 
53
44
 
45
+ @dataclass
46
+ class ClientActionGroup:
47
+
48
+ name: str
49
+ actions: list[ClientAction] = field(default_factory=list)
50
+ icon: Icon | type[Enum] = None
51
+ icon_only: bool = False
52
+
53
+
54
54
  class TableFieldAlignment(Enum):
55
55
 
56
56
  LEFT = 'left'
@@ -1,4 +1,3 @@
1
- import time
2
1
  import logging
3
2
  from django.db.models.fields.related import ManyToOneRel, ManyToManyRel
4
3
  from django.core.cache import cache
@@ -301,10 +300,11 @@ class Filter:
301
300
  and not isinstance(x, (ManyToOneRel, ManyToManyRel)),
302
301
  self.model._meta.get_fields()
303
302
  )]
304
- fields.extend([
305
- (x['annotation'].verbose_name, x['name'])
306
- for x in self.model.get_annotations()
307
- ])
303
+ if hasattr(self.model, 'get_annotations'):
304
+ fields.extend([
305
+ (x['annotation'].verbose_name, x['name'])
306
+ for x in self.model.get_annotations()
307
+ ])
308
308
  sorted_fields = sorted(fields, key=lambda x: x[0].lower())
309
309
  for field in sorted_fields:
310
310
  html += f"""
@@ -20928,12 +20928,6 @@ select:focus {
20928
20928
  border-bottom-right-radius: 0;
20929
20929
  }
20930
20930
 
20931
- #list-customization * .dropdown-menu {
20932
- width: 292px;
20933
- border-top-left-radius: 0;
20934
- border-top-right-radius: 0;
20935
- }
20936
-
20937
20931
  @media screen and (max-width: 768px) {
20938
20932
  table.has-box * td {
20939
20933
  width: 100%;
@@ -20961,6 +20955,23 @@ select:focus {
20961
20955
  display: inline-block;
20962
20956
  }
20963
20957
  }
20958
+ /* Chrome, Safari, Edge, Opera */
20959
+ input::-webkit-outer-spin-button,
20960
+ input::-webkit-inner-spin-button {
20961
+ -webkit-appearance: none;
20962
+ margin: 0;
20963
+ }
20964
+
20965
+ /* Firefox */
20966
+ input[type=number] {
20967
+ -moz-appearance: textfield;
20968
+ }
20969
+
20970
+ /* Fix CKEditor List Display */
20971
+ .ck-editor__editable_inline {
20972
+ padding: 0 30px !important;
20973
+ }
20974
+
20964
20975
  @media screen and (max-width: 1407px) {
20965
20976
  #list-customization * .dropdown-menu {
20966
20977
  width: auto;