ex4nicegui 0.3.0__tar.gz → 0.3.1__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 (98) hide show
  1. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/PKG-INFO +1 -1
  2. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/__init__.py +1 -1
  3. ex4nicegui-0.3.1/ex4nicegui/bi/__init__.py +13 -0
  4. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/dataSource.py +66 -37
  5. ex4nicegui-0.3.1/ex4nicegui/bi/dataSourceFacade.py +148 -0
  6. ex4nicegui-0.3.1/ex4nicegui/bi/elements/containers.py +13 -0
  7. ex4nicegui-0.3.1/ex4nicegui/bi/elements/layouts.py +28 -0
  8. ex4nicegui-0.3.1/ex4nicegui/bi/elements/models.py +55 -0
  9. ex4nicegui-0.3.1/ex4nicegui/bi/elements/text.py +33 -0
  10. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_aggrid.py +46 -0
  11. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_date_picker.js +35 -0
  12. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_date_picker.py +77 -0
  13. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_echarts.py +72 -0
  14. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_radio.py +60 -0
  15. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_range.py +119 -0
  16. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_select.py +105 -0
  17. ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_slider.py +59 -0
  18. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/protocols.py +52 -5
  19. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/types.py +2 -1
  20. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/EChartsComponent/ECharts.py +1 -0
  21. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/base.py +12 -1
  22. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/button.py +1 -1
  23. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/drawer.py +1 -2
  24. ex4nicegui-0.3.1/ex4nicegui/utils/__init__.py +0 -0
  25. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/utils/signals.py +4 -0
  26. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/PKG-INFO +1 -1
  27. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/SOURCES.txt +13 -0
  28. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/requires.txt +1 -1
  29. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/setup.py +1 -1
  30. ex4nicegui-0.3.0/ex4nicegui/bi/__init__.py +0 -3
  31. ex4nicegui-0.3.0/ex4nicegui/bi/dataSourceFacade.py +0 -263
  32. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/LICENSE +0 -0
  33. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/README.md +0 -0
  34. {ex4nicegui-0.3.0/ex4nicegui/reactive/EChartsComponent → ex4nicegui-0.3.1/ex4nicegui/bi/elements}/__init__.py +0 -0
  35. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/index.py +0 -0
  36. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/experimental_/__init__.py +0 -0
  37. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/experimental_/gridLayout/__init__.py +0 -0
  38. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/experimental_/gridLayout/index.py +0 -0
  39. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/__init__.py +0 -0
  40. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/GridFlex.js +0 -0
  41. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/__init__.py +0 -0
  42. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/gridFlex.py +0 -0
  43. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/utils.py +0 -0
  44. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/rxFlex/__init__.py +0 -0
  45. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/rxFlex/index.py +0 -0
  46. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/rxFlex/types.py +0 -0
  47. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/EChartsComponent/ECharts.js +0 -0
  48. {ex4nicegui-0.3.0/ex4nicegui/reactive/UseDraggable → ex4nicegui-0.3.1/ex4nicegui/reactive/EChartsComponent}/__init__.py +0 -0
  49. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/UseDraggable/UseDraggable.js +0 -0
  50. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/UseDraggable/UseDraggable.py +0 -0
  51. {ex4nicegui-0.3.0/ex4nicegui/reactive/dropZone → ex4nicegui-0.3.1/ex4nicegui/reactive/UseDraggable}/__init__.py +0 -0
  52. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/__index.py +0 -0
  53. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/__init__.py +0 -0
  54. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/drawer.py +0 -0
  55. {ex4nicegui-0.3.0/ex4nicegui/reactive/useMouse → ex4nicegui-0.3.1/ex4nicegui/reactive/dropZone}/__init__.py +0 -0
  56. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/dropZone/dropZone.js +0 -0
  57. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/dropZone/dropZone.py +0 -0
  58. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/fileWatcher.py +0 -0
  59. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/local_file_picker.py +0 -0
  60. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/__init__.py +0 -0
  61. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/aggrid.py +0 -0
  62. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/card.py +0 -0
  63. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/checkbox.py +0 -0
  64. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/color_picker.py +0 -0
  65. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/column.py +0 -0
  66. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/date.py +0 -0
  67. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/echarts.py +0 -0
  68. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/expansion.py +0 -0
  69. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/grid.py +0 -0
  70. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/html.py +0 -0
  71. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/icon.py +0 -0
  72. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/image.py +0 -0
  73. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/input.py +0 -0
  74. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/label.py +0 -0
  75. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/number.py +0 -0
  76. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/radio.py +0 -0
  77. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/row.py +0 -0
  78. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/select.py +0 -0
  79. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/slider.py +0 -0
  80. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/switch.py +0 -0
  81. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/table.py +0 -0
  82. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/textarea.py +0 -0
  83. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/upload.py +0 -0
  84. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/utils.py +0 -0
  85. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/q_pagination.py +0 -0
  86. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/rxui.py +0 -0
  87. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/useMouse/UseMouse.js +0 -0
  88. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/useMouse/UseMouse.py +0 -0
  89. {ex4nicegui-0.3.0/ex4nicegui/utils → ex4nicegui-0.3.1/ex4nicegui/reactive/useMouse}/__init__.py +0 -0
  90. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/usePagination.py +0 -0
  91. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/tools/__init__.py +0 -0
  92. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/tools/debug.py +0 -0
  93. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/utils/clientScope.py +0 -0
  94. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/utils/common.py +0 -0
  95. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/dependency_links.txt +0 -0
  96. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/not-zip-safe +0 -0
  97. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/top_level.txt +0 -0
  98. {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ex4nicegui
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: ...
5
5
  Home-page:
6
6
  Author: carson_jia
@@ -16,4 +16,4 @@ from signe import batch
16
16
  from ex4nicegui.experimental_ import gridLayout as exp_ui
17
17
 
18
18
 
19
- __version__ = "0.3.0"
19
+ __version__ = "0.3.1"
@@ -0,0 +1,13 @@
1
+ from .index import data_source
2
+ from .elements.text import ui_title, ui_header, ui_subheader
3
+ from .elements.containers import ui_cols
4
+ from .elements.layouts import ui_left_drawer
5
+
6
+ __all__ = [
7
+ "data_source",
8
+ "ui_left_drawer",
9
+ "ui_title",
10
+ "ui_header",
11
+ "ui_subheader",
12
+ "ui_cols",
13
+ ]
@@ -1,16 +1,12 @@
1
- from typing import Dict, List, Optional, cast
1
+ from typing import Callable, Dict, List, Optional, Set, cast
2
2
  from ex4nicegui import to_ref, ref_computed, on
3
- from nicegui import globals, Client
3
+ from nicegui import globals as ng_globals, Client, ui
4
4
 
5
- from dataclasses import dataclass
5
+ from dataclasses import dataclass, field
6
6
  from . import types
7
7
  from .protocols import IDataSourceAble
8
8
 
9
-
10
- @dataclass
11
- class DataSourceInfo:
12
- source: "DataSource"
13
- update_callback: types._TSourceBuildFn
9
+ _TComponentUpdateCallback = Callable[[], None]
14
10
 
15
11
 
16
12
  @dataclass
@@ -27,8 +23,12 @@ class ComponentInfoKey:
27
23
  @dataclass
28
24
  class ComponentInfo:
29
25
  key: ComponentInfoKey
30
- update_callback: types._TComponentUpdateCallback
26
+ update_callback: Optional[_TComponentUpdateCallback] = None
31
27
  filter: Optional[Filter] = None
28
+ exclude_keys: Set[ComponentInfoKey] = field(default_factory=set)
29
+
30
+ def __eq__(self, other):
31
+ return isinstance(other, ComponentInfo) and self.key == other.key
32
32
 
33
33
 
34
34
  class ComponentMap:
@@ -56,9 +56,10 @@ class ComponentMap:
56
56
  if client_id in self._client_map:
57
57
  del self._client_map[client_id]
58
58
 
59
- def has_record(self, client_id: types._TNgClientID, element_id: types._TElementID):
59
+ def has_record(self, key: ComponentInfoKey):
60
60
  return (
61
- client_id in self._client_map and element_id in self._client_map[client_id]
61
+ key.client_id in self._client_map
62
+ and key.element_id in self._client_map[key.client_id]
62
63
  )
63
64
 
64
65
  def set_filter(
@@ -74,6 +75,9 @@ class ComponentMap:
74
75
  info for ele_map in self._client_map.values() for info in ele_map.values()
75
76
  )
76
77
 
78
+ def get_info(self, key: ComponentInfoKey) -> ComponentInfo:
79
+ return self._client_map[key.client_id][key.element_id]
80
+
77
81
 
78
82
  class DataSource:
79
83
  _global_id_count: types._TDataSourceId = 0
@@ -118,12 +122,33 @@ class DataSource:
118
122
  def id(self):
119
123
  return self.__id
120
124
 
125
+ def get_component_info_key(self, element_id: types._TElementID):
126
+ client_id = ng_globals.get_client().id
127
+ return ComponentInfoKey(client_id, element_id)
128
+
129
+ def get_filtered_data(self, element: ui.element):
130
+ data = self._idataSource.get_data()
131
+
132
+ # note:must be use client id of the element
133
+ key = ComponentInfoKey(element.client.id, element.id)
134
+ current_info = self._component_map.get_info(key)
135
+
136
+ filters = [
137
+ info.filter.callback
138
+ for info in self._component_map.get_all_info()
139
+ if current_info.key != info.key
140
+ and (info.key not in current_info.exclude_keys)
141
+ and info.filter
142
+ ]
143
+
144
+ return self._idataSource.apply_filters(data, filters)
145
+
121
146
  def _register_component(
122
147
  self,
123
148
  element_id: types._TElementID,
124
- update_callback: types._TComponentUpdateCallback,
149
+ update_callback: Optional[_TComponentUpdateCallback] = None,
125
150
  ):
126
- ng_client = globals.get_client()
151
+ ng_client = ng_globals.get_client()
127
152
  client_id = ng_client.id
128
153
 
129
154
  if not self._component_map.has_client_record(client_id):
@@ -133,42 +158,46 @@ class DataSource:
133
158
  if not e.shared:
134
159
  self._component_map.remove_client(e.id)
135
160
 
136
- self._component_map.add_info(
137
- ComponentInfo(ComponentInfoKey(client_id, element_id), update_callback)
138
- )
161
+ info = ComponentInfo(ComponentInfoKey(client_id, element_id), update_callback)
162
+ self._component_map.add_info(info)
139
163
 
140
- return self
164
+ return info
141
165
 
142
166
  def send_filter(self, element_id: types._TElementID, filter: Filter):
143
- client_id = globals.get_client().id
167
+ client_id = ng_globals.get_client().id
168
+ key = ComponentInfoKey(client_id, element_id)
144
169
 
145
- if not self._component_map.has_record(client_id, element_id):
170
+ if not self._component_map.has_record(key):
146
171
  raise ValueError("element not register")
147
172
 
148
173
  self._component_map.set_filter(client_id, element_id, filter)
149
174
 
150
- self.__notify_update([ComponentInfoKey(client_id, element_id)])
151
- return self
175
+ trigger_info = self._component_map.get_info(
176
+ ComponentInfoKey(client_id, element_id)
177
+ )
152
178
 
153
- def __notify_update(self, ignore_keys: Optional[List[ComponentInfoKey]] = None):
154
- ignore_keys = ignore_keys or []
155
- ignore_ids_set = set(ignore_keys)
179
+ self.__notify_update(trigger_info)
180
+ self.__filters.value = [
181
+ info.filter for info in self._component_map.get_all_info() if info.filter
182
+ ]
156
183
 
184
+ return self
185
+
186
+ def __notify_update(self, trigger_info: Optional[ComponentInfo] = None):
157
187
  # nodify every component
158
188
  for current_info in self._component_map.get_all_info():
159
- if current_info.key in ignore_ids_set:
189
+ # not nodify the self triggering
190
+ if trigger_info and current_info.key == trigger_info.key:
160
191
  continue
161
192
 
162
- # apply filters ,except current target
163
- filters = [
164
- info.filter.callback
165
- for info in self._component_map.get_all_info()
166
- if (info.key != current_info.key) and info.filter
167
- ]
168
-
169
- new_data = self._idataSource.apply_filters(self.__data.value, filters)
170
- current_info.update_callback(new_data)
193
+ update_callback = current_info.update_callback
194
+ if update_callback:
195
+ update_callback()
171
196
 
172
- self.__filters.value = [
173
- info.filter for info in self._component_map.get_all_info() if info.filter
174
- ]
197
+ def on_source_update(
198
+ self,
199
+ element_id: types._TElementID,
200
+ callback: _TComponentUpdateCallback,
201
+ ):
202
+ key = self.get_component_info_key(element_id)
203
+ self._component_map.get_info(key).update_callback = callback
@@ -0,0 +1,148 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Callable, Dict, TypeVar, Generic, Union, cast
3
+ from nicegui import ui
4
+ from .dataSource import DataSource, Filter
5
+ from . import types as bi_types
6
+ from .elements.ui_select import ui_select
7
+ from .elements.ui_radio import ui_radio
8
+ from .elements.ui_slider import ui_slider
9
+ from .elements.ui_range import ui_range
10
+ from .elements.ui_echarts import ui_echarts
11
+ from .elements.ui_aggrid import ui_aggrid
12
+
13
+
14
+ _TData = TypeVar("_TData")
15
+
16
+
17
+ class DataSourceFacade(Generic[_TData]):
18
+ def __init__(self, ds: DataSource) -> None:
19
+ self._dataSource = ds
20
+
21
+ @property
22
+ def data(self) -> _TData:
23
+ """Data without any filtering"""
24
+ return cast(_TData, self._dataSource.data)
25
+
26
+ @property
27
+ def filtered_data(self) -> _TData:
28
+ """Data after filtering"""
29
+ return cast(_TData, self._dataSource.filtered_data)
30
+
31
+ def ui_select(self, column: str, *, clearable=True, multiple=True, **kwargs):
32
+ """
33
+ Creates a user interface select box.
34
+
35
+ Parameters:
36
+ column (str): The column name of the data source.
37
+ clearable (bool, optional): Whether to allow clearing the content of the select box. Default is True.
38
+ multiple (bool, optional): Whether to allow multiple selections.
39
+ **kwargs: Additional optional parameters that will be passed to the ui.select constructor.
40
+
41
+ Returns:
42
+ SelectResult: An instance of a user interface select box.
43
+ """
44
+ kws = {key: value for key, value in locals().items() if key not in ("kwargs")}
45
+ kws.update(kwargs)
46
+ return ui_select(**kws)
47
+
48
+ def ui_aggrid(self, **kwargs):
49
+ """
50
+ Creates aggrid table.
51
+
52
+ Parameters:
53
+ **kwargs: Additional optional parameters that will be passed to the ui.aggrid constructor.
54
+
55
+ Returns:
56
+ ui.aggrid: aggrid table.
57
+ """
58
+ return ui_aggrid(self, **kwargs)
59
+
60
+ def ui_radio(self, column: str, **kwargs):
61
+ """
62
+ Creates radio Selection.
63
+
64
+ Parameters:
65
+ column (str): The column name of the data source.
66
+ **kwargs: Additional optional parameters that will be passed to the ui.radio constructor.
67
+
68
+ Returns:
69
+ RadioResult: An radio Selection.
70
+ """
71
+ kws = {key: value for key, value in locals().items() if key not in ("kwargs")}
72
+ kws.update(kwargs)
73
+ return ui_radio(**kws)
74
+
75
+ def ui_slider(self, column: str, **kwargs):
76
+ """
77
+ Creates Slider.
78
+
79
+ Parameters:
80
+ column (str): The column name of the data source.
81
+ **kwargs: Additional optional parameters that will be passed to the ui.slider constructor.
82
+
83
+ Returns:
84
+ ui.radio: An Slider.
85
+ """
86
+ kws = {key: value for key, value in locals().items() if key not in ("kwargs")}
87
+ kws.update(kwargs)
88
+ return ui_slider(**kws)
89
+
90
+ def ui_range(self, column: str, **kwargs):
91
+ """
92
+ Creates Range.
93
+
94
+ Parameters:
95
+ column (str): The column name of the data source.
96
+ **kwargs: Additional optional parameters that will be passed to the ui.slider constructor.
97
+
98
+ Returns:
99
+ QRange: An Range.
100
+ """
101
+ kws = {key: value for key, value in locals().items() if key not in ("kwargs")}
102
+ kws.update(kwargs)
103
+ return ui_range(**kws)
104
+
105
+ def ui_echarts(
106
+ self, fn: Callable[[Any], Union[Dict, "pyecharts.Base"]] # pyright: ignore
107
+ ):
108
+ """Create charts
109
+
110
+ Args:
111
+ fn (Callable[[Any], Union[Dict, "pyecharts.Base"]]): builder function.
112
+
113
+ ## Examples
114
+
115
+ Support pyecharts
116
+
117
+ ```py
118
+ import pandas as pd
119
+ from ex4nicegui import bi
120
+ from pyecharts.charts import Bar
121
+
122
+ df = pd.DataFrame({"name": list("abcdc"), "value": range(5)})
123
+ ds = bi.data_source(df)
124
+
125
+ @ds.ui_echarts
126
+ def bar(data: pd.DataFrame):
127
+ c = (
128
+ Bar()
129
+ .add_xaxis(data["name"].tolist())
130
+ .add_yaxis("value", data["value"].tolist())
131
+ )
132
+
133
+ return c
134
+
135
+ bar.classes("h-[20rem]")
136
+ ```
137
+
138
+ """
139
+ return ui_echarts(self, fn)
140
+
141
+ def send_filter(
142
+ self, element: ui.element, filter: bi_types._TFilterCallback[_TData]
143
+ ):
144
+ ele_id = element.id
145
+ key = self._dataSource.get_component_info_key(ele_id)
146
+ if not self._dataSource._component_map.has_record(key):
147
+ self._dataSource._register_component(ele_id)
148
+ self._dataSource.send_filter(ele_id, Filter(filter))
@@ -0,0 +1,13 @@
1
+ from nicegui import ui
2
+ from ex4nicegui.layout import grid_box
3
+
4
+
5
+ def ui_cols(num: int, min_width="0"):
6
+ with grid_box(template_columns=f"repeat({num},1fr)").classes(
7
+ "justify-between"
8
+ ) as gb:
9
+ divs = [ui.column() for _ in range(num)]
10
+
11
+ gb.grid_box(template_columns="1fr", break_point="<sm[0-599.99px]")
12
+
13
+ return divs
@@ -0,0 +1,28 @@
1
+ from nicegui import ui
2
+ from ex4nicegui.reactive import rxui
3
+ from ex4nicegui import to_ref
4
+
5
+
6
+ def ui_left_drawer():
7
+ drawer_show = to_ref(True)
8
+
9
+ with rxui.drawer("left", value=drawer_show) as drawer:
10
+ with ui.page_sticky("top-right", x_offset=10, y_offset=10):
11
+ icon_close = (
12
+ rxui.icon(name="close")
13
+ .classes("cursor-pointer")
14
+ .props("round ")
15
+ .bind_visible(drawer_show)
16
+ )
17
+ icon_close.on("click", drawer.toggle)
18
+
19
+ with ui.page_sticky("top-left", x_offset=10, y_offset=10):
20
+ icon_close = (
21
+ rxui.icon(name="keyboard_arrow_right", size="1.2rem")
22
+ .classes("cursor-pointer")
23
+ .props("round ")
24
+ .bind_not_visible(drawer_show)
25
+ )
26
+ icon_close.on("click", drawer.toggle)
27
+
28
+ return drawer.element
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+ from typing import Optional, TypeVar, Generic, TYPE_CHECKING, Union
3
+ from nicegui import ui
4
+
5
+ if TYPE_CHECKING:
6
+ from ex4nicegui.bi.dataSource import DataSource
7
+
8
+
9
+ _T_ELEMENT = TypeVar("_T_ELEMENT", bound=ui.element)
10
+
11
+
12
+ class UiResult(Generic[_T_ELEMENT]):
13
+ def __init__(self, element: _T_ELEMENT, dataSource: "DataSource") -> None:
14
+ self.__element = element
15
+ self._dataSource = dataSource
16
+
17
+ @property
18
+ def element(self):
19
+ return self.__element
20
+
21
+ @property
22
+ def id(self):
23
+ return self.element.id
24
+
25
+ def classes(
26
+ self,
27
+ add: Optional[str] = None,
28
+ *,
29
+ remove: Optional[str] = None,
30
+ replace: Optional[str] = None,
31
+ ):
32
+ self.element.classes(add, remove=remove, replace=replace)
33
+ return self
34
+
35
+ def props(
36
+ self,
37
+ add: Optional[str] = None,
38
+ *,
39
+ remove: Optional[str] = None,
40
+ ):
41
+ self.element.props(add, remove=remove)
42
+ return self
43
+
44
+ def cancel_linkage(self, *source: Union[ui.element, "UiResult"]):
45
+ get_info_key = self._dataSource.get_component_info_key
46
+
47
+ key = get_info_key(self.element.id)
48
+
49
+ info = self._dataSource._component_map.get_info(key)
50
+
51
+ for s in source:
52
+ res_key = get_info_key(s.id)
53
+ info.exclude_keys.add(res_key)
54
+
55
+ return self
@@ -0,0 +1,33 @@
1
+ from typing import Callable, Any, Union
2
+ from nicegui import ui
3
+ from ex4nicegui import effect
4
+
5
+
6
+ _T_Maybe_Callable = Any
7
+
8
+
9
+ def _ui_label(text_or_build: _T_Maybe_Callable):
10
+ label = ui.label()
11
+
12
+ if isinstance(text_or_build, Callable):
13
+
14
+ @effect
15
+ def _():
16
+ label.text = text_or_build()
17
+
18
+ else:
19
+ label.text = str(text_or_build)
20
+
21
+ return label
22
+
23
+
24
+ def ui_title(text_or_build: _T_Maybe_Callable):
25
+ return _ui_label(text_or_build).style("font-size: calc(1.4rem + 1.8vw)")
26
+
27
+
28
+ def ui_header(text_or_build: _T_Maybe_Callable):
29
+ return _ui_label(text_or_build).style("font-size: calc(1.35rem + 1.2vw)")
30
+
31
+
32
+ def ui_subheader(text_or_build: _T_Maybe_Callable):
33
+ return _ui_label(text_or_build).style("font-size: calc(1.3rem + .6vw)")
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, Union, cast
3
+ from nicegui import ui
4
+ from nicegui.events import UiEventArguments
5
+ from ex4nicegui.reactive import rxui
6
+ from ex4nicegui.reactive.EChartsComponent.ECharts import (
7
+ EChartsClickEventArguments,
8
+ echarts,
9
+ )
10
+ from ex4nicegui.bi.dataSource import DataSource
11
+ from .models import UiResult
12
+
13
+ if TYPE_CHECKING:
14
+ from ex4nicegui.bi.dataSourceFacade import DataSourceFacade
15
+
16
+
17
+ class AggridResult(UiResult[ui.aggrid]):
18
+ def __init__(
19
+ self, element: ui.aggrid, dataSource: DataSource, table_update: Callable
20
+ ) -> None:
21
+ super().__init__(element, dataSource)
22
+ self.table_update = table_update
23
+
24
+ def cancel_linkage(self, *source: Union[ui.element, "UiResult"]):
25
+ super().cancel_linkage(*source)
26
+ self.table_update()
27
+
28
+
29
+ def ui_aggrid(
30
+ self: DataSourceFacade,
31
+ **kwargs,
32
+ ):
33
+ kwargs.update({"options": {}})
34
+
35
+ cp = ui.aggrid(**kwargs)
36
+
37
+ def on_source_update():
38
+ data = self._dataSource.get_filtered_data(cp)
39
+ cp._props["options"] = self._dataSource._idataSource.get_aggrid_options(data)
40
+ cp.update()
41
+
42
+ info = self._dataSource._register_component(cp.id, on_source_update)
43
+
44
+ on_source_update()
45
+
46
+ return AggridResult(cp, self._dataSource, on_source_update)
@@ -0,0 +1,35 @@
1
+ export default {
2
+ template: `
3
+ <div :id="'cus-'+id" class="q-pa-md" style="max-width: 300px">
4
+ <q-input filled v-model="value" mask="date" :rules="['date']">
5
+ <template v-slot:append>
6
+ <q-icon name="event" class="cursor-pointer">
7
+ <q-popup-proxy cover transition-show="scale" transition-hide="scale">
8
+ <q-date v-model="value" >
9
+ </q-date>
10
+ </q-popup-proxy>
11
+ </q-icon>
12
+ </template>
13
+ </q-input>
14
+ </div>
15
+ `,
16
+ props: {
17
+ id: String,
18
+ date: String,
19
+ },
20
+ data() {
21
+ return {
22
+ value: this.date
23
+ }
24
+ },
25
+ watch: {
26
+ value(newValue) {
27
+ this.$emit("update:value", newValue);
28
+ },
29
+ },
30
+ computed: {
31
+ },
32
+ methods: {
33
+
34
+ },
35
+ };
@@ -0,0 +1,77 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Optional
3
+ from nicegui import ui
4
+ from nicegui.client import Client
5
+ from nicegui.elements.select import Select
6
+ from ex4nicegui import to_ref, ref_computed
7
+ from ex4nicegui.utils.signals import Ref
8
+ from ex4nicegui.bi.dataSource import Filter
9
+ from .models import UiResult
10
+
11
+ if TYPE_CHECKING:
12
+ from ex4nicegui.bi.dataSourceFacade import DataSourceFacade, DataSource
13
+
14
+
15
+ class UiDatePicker(ui.element, component="ui_date_picker.js"):
16
+ def __init__(self, date: str) -> None:
17
+ super().__init__()
18
+ self._props["id"] = self.id
19
+ self.value = date.replace("-", "/")
20
+ self._props["date"] = self.value
21
+
22
+
23
+ class DatePickerResult(UiResult[UiDatePicker]):
24
+ def __init__(
25
+ self,
26
+ element: UiDatePicker,
27
+ dataSource: DataSource,
28
+ ref_value: Ref,
29
+ ) -> None:
30
+ super().__init__(element, dataSource)
31
+ self._ref_value = ref_value
32
+
33
+ @property
34
+ def value(self) -> str:
35
+ return self._ref_value.value
36
+
37
+
38
+ def ui_date_picker(
39
+ self: DataSourceFacade, column: str, *, value: Optional[str] = None, **kwargs
40
+ ):
41
+ options = self._dataSource._idataSource.duplicates_column_values(self.data, column)
42
+ kwargs.update(
43
+ {
44
+ "options": options,
45
+ "label": column,
46
+ }
47
+ )
48
+
49
+ cp = UiDatePicker(value or "")
50
+ ref_value = to_ref(cp.value)
51
+
52
+ def onchange(e):
53
+ value = e.args
54
+
55
+ cp.value = value
56
+ ref_value.value = value # type: ignore
57
+
58
+ def data_filter(data):
59
+ if cp.value is None or not cp.value:
60
+ return data
61
+
62
+ cond = None
63
+ cond = data[column] == cp.value
64
+ return data[cond]
65
+
66
+ self._dataSource.send_filter(cp.id, Filter(data_filter))
67
+
68
+ cp.on("update:value", onchange)
69
+
70
+ def on_source_update():
71
+ data = self._dataSource.get_filtered_data(cp)
72
+ # options = self._dataSource._idataSource.duplicates_column_values(data, column)
73
+ # value = cp.value
74
+
75
+ self._dataSource._register_component(cp.id, on_source_update)
76
+
77
+ return DatePickerResult(cp, self._dataSource, ref_value)