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.
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/PKG-INFO +1 -1
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/__init__.py +1 -1
- ex4nicegui-0.3.1/ex4nicegui/bi/__init__.py +13 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/dataSource.py +66 -37
- ex4nicegui-0.3.1/ex4nicegui/bi/dataSourceFacade.py +148 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/containers.py +13 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/layouts.py +28 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/models.py +55 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/text.py +33 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_aggrid.py +46 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_date_picker.js +35 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_date_picker.py +77 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_echarts.py +72 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_radio.py +60 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_range.py +119 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_select.py +105 -0
- ex4nicegui-0.3.1/ex4nicegui/bi/elements/ui_slider.py +59 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/protocols.py +52 -5
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/types.py +2 -1
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/EChartsComponent/ECharts.py +1 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/base.py +12 -1
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/button.py +1 -1
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/drawer.py +1 -2
- ex4nicegui-0.3.1/ex4nicegui/utils/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/utils/signals.py +4 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/PKG-INFO +1 -1
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/SOURCES.txt +13 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/requires.txt +1 -1
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/setup.py +1 -1
- ex4nicegui-0.3.0/ex4nicegui/bi/__init__.py +0 -3
- ex4nicegui-0.3.0/ex4nicegui/bi/dataSourceFacade.py +0 -263
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/LICENSE +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/README.md +0 -0
- {ex4nicegui-0.3.0/ex4nicegui/reactive/EChartsComponent → ex4nicegui-0.3.1/ex4nicegui/bi/elements}/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/bi/index.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/experimental_/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/experimental_/gridLayout/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/experimental_/gridLayout/index.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/GridFlex.js +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/gridFlex.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/gridFlex/utils.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/rxFlex/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/rxFlex/index.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/layout/rxFlex/types.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/EChartsComponent/ECharts.js +0 -0
- {ex4nicegui-0.3.0/ex4nicegui/reactive/UseDraggable → ex4nicegui-0.3.1/ex4nicegui/reactive/EChartsComponent}/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/UseDraggable/UseDraggable.js +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/UseDraggable/UseDraggable.py +0 -0
- {ex4nicegui-0.3.0/ex4nicegui/reactive/dropZone → ex4nicegui-0.3.1/ex4nicegui/reactive/UseDraggable}/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/__index.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/drawer.py +0 -0
- {ex4nicegui-0.3.0/ex4nicegui/reactive/useMouse → ex4nicegui-0.3.1/ex4nicegui/reactive/dropZone}/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/dropZone/dropZone.js +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/dropZone/dropZone.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/fileWatcher.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/local_file_picker.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/aggrid.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/card.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/checkbox.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/color_picker.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/column.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/date.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/echarts.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/expansion.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/grid.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/html.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/icon.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/image.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/input.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/label.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/number.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/radio.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/row.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/select.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/slider.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/switch.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/table.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/textarea.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/upload.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/officials/utils.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/q_pagination.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/rxui.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/useMouse/UseMouse.js +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/useMouse/UseMouse.py +0 -0
- {ex4nicegui-0.3.0/ex4nicegui/utils → ex4nicegui-0.3.1/ex4nicegui/reactive/useMouse}/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/reactive/usePagination.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/tools/__init__.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/tools/debug.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/utils/clientScope.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui/utils/common.py +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/dependency_links.txt +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/not-zip-safe +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/ex4nicegui.egg-info/top_level.txt +0 -0
- {ex4nicegui-0.3.0 → ex4nicegui-0.3.1}/setup.cfg +0 -0
|
@@ -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:
|
|
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,
|
|
59
|
+
def has_record(self, key: ComponentInfoKey):
|
|
60
60
|
return (
|
|
61
|
-
client_id in self._client_map
|
|
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:
|
|
149
|
+
update_callback: Optional[_TComponentUpdateCallback] = None,
|
|
125
150
|
):
|
|
126
|
-
ng_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
|
-
|
|
137
|
-
|
|
138
|
-
)
|
|
161
|
+
info = ComponentInfo(ComponentInfoKey(client_id, element_id), update_callback)
|
|
162
|
+
self._component_map.add_info(info)
|
|
139
163
|
|
|
140
|
-
return
|
|
164
|
+
return info
|
|
141
165
|
|
|
142
166
|
def send_filter(self, element_id: types._TElementID, filter: Filter):
|
|
143
|
-
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(
|
|
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.
|
|
151
|
-
|
|
175
|
+
trigger_info = self._component_map.get_info(
|
|
176
|
+
ComponentInfoKey(client_id, element_id)
|
|
177
|
+
)
|
|
152
178
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
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
|
-
|
|
189
|
+
# not nodify the self triggering
|
|
190
|
+
if trigger_info and current_info.key == trigger_info.key:
|
|
160
191
|
continue
|
|
161
192
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
173
|
-
|
|
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)
|