dara-components 1.8.5__py3-none-any.whl → 1.22.1__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.
- dara/components/__init__.py +18 -0
- dara/components/_assets/__init__.py +30 -0
- dara/components/_assets/auto_js/.gitkeep +0 -0
- dara/components/_assets/auto_js/dara.components.css +1494 -0
- dara/components/_assets/auto_js/dara.components.umd.js +182837 -0
- dara/components/_assets/common/bokeh-3.1.1.min.js +690 -0
- dara/components/_assets/common/bokeh-api-3.1.1.min.js +60 -0
- dara/components/_assets/common/bokeh-gl-3.1.1.min.js +67 -0
- dara/components/_assets/common/bokeh-mathjax-3.1.1.min.js +329 -0
- dara/components/_assets/common/bokeh-tables-3.1.1.min.js +132 -0
- dara/components/_assets/common/bokeh-widgets-3.1.1.min.js +129 -0
- dara/components/_assets/common/pixi-filters.min.js +17 -0
- dara/components/_assets/common/pixi.min.js +2214 -0
- dara/components/_assets/common/pixi_viewport.js +1 -0
- dara/components/_assets/common/plotly.min.js +8 -0
- dara/components/common/__init__.py +11 -2
- dara/components/common/accordion.py +20 -26
- dara/components/common/anchor.py +9 -10
- dara/components/common/base_component.py +23 -36
- dara/components/common/bullet_list.py +1 -3
- dara/components/common/button.py +35 -26
- dara/components/common/button_bar.py +25 -20
- dara/components/common/card.py +4 -5
- dara/components/common/carousel.py +9 -9
- dara/components/common/checkbox_group.py +26 -19
- dara/components/common/code.py +8 -5
- dara/components/common/component_select_list.py +9 -13
- dara/components/common/datepicker.py +16 -16
- dara/components/common/dropdown_menu.py +161 -0
- dara/components/common/dropzone.py +42 -33
- dara/components/common/form.py +5 -7
- dara/components/common/form_page.py +4 -6
- dara/components/common/grid.py +21 -18
- dara/components/common/heading.py +5 -4
- dara/components/common/icon.py +1 -3
- dara/components/common/if_cmp.py +23 -17
- dara/components/common/image.py +2 -2
- dara/components/common/input.py +9 -11
- dara/components/common/label.py +13 -14
- dara/components/common/markdown.py +3 -5
- dara/components/common/modal.py +2 -2
- dara/components/common/overlay.py +8 -14
- dara/components/common/paragraph.py +2 -2
- dara/components/common/progress_bar.py +6 -8
- dara/components/common/radio_group.py +38 -21
- dara/components/common/select.py +33 -30
- dara/components/common/slider.py +74 -29
- dara/components/common/spacer.py +4 -6
- dara/components/common/stack.py +7 -4
- dara/components/common/switch.py +6 -8
- dara/components/common/tabbed_card.py +8 -11
- dara/components/common/table.py +224 -73
- dara/components/common/text.py +7 -9
- dara/components/common/textarea.py +7 -7
- dara/components/common/time_utils.py +2 -5
- dara/components/common/tooltip.py +4 -6
- dara/components/common/utils.py +29 -35
- dara/components/graphs/__init__.py +1 -0
- dara/components/graphs/components/base_graph_component.py +34 -22
- dara/components/graphs/components/causal_graph_viewer.py +13 -15
- dara/components/graphs/components/edge_encoder.py +49 -26
- dara/components/graphs/components/node_hierarchy_builder.py +17 -16
- dara/components/graphs/definitions.py +27 -20
- dara/components/graphs/graph_layout.py +90 -53
- dara/components/plotting/__init__.py +2 -1
- dara/components/plotting/bokeh/bokeh.py +7 -10
- dara/components/plotting/bokeh/utils.py +5 -3
- dara/components/plotting/plotly/plotly.py +24 -19
- dara/components/plotting/plotly/themes.py +7 -5
- dara/components/smart/__init__.py +7 -1
- dara/components/smart/chat/chat.py +7 -8
- dara/components/smart/chat/config.py +1 -1
- dara/components/smart/chat/types.py +4 -6
- dara/components/smart/code_editor/code_editor.py +18 -4
- dara/components/smart/code_editor/util.py +11 -11
- dara/components/smart/data_slicer/__init__.py +4 -0
- dara/components/smart/data_slicer/data_slicer.py +14 -18
- dara/components/smart/data_slicer/data_slicer_modal.py +4 -6
- dara/components/smart/data_slicer/extension/data_slicer_filter.py +3 -4
- dara/components/smart/data_slicer/extension/filter_status_button.py +1 -3
- dara/components/smart/data_slicer/utils/core.py +23 -23
- dara/components/smart/data_slicer/utils/data_preview.py +1 -3
- dara/components/smart/data_slicer/utils/plotting.py +8 -6
- dara/components/smart/hierarchy.py +9 -10
- {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/METADATA +7 -7
- dara_components-1.22.1.dist-info/RECORD +100 -0
- {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/WHEEL +1 -1
- dara_components-1.22.1.dist-info/entry_points.txt +3 -0
- dara/components/umd/dara.components.umd.js +0 -396288
- dara/components/umd/style.css +0 -745
- dara_components-1.8.5.dist-info/RECORD +0 -86
- {dara_components-1.8.5.dist-info → dara_components-1.22.1.dist-info}/LICENSE +0 -0
|
@@ -15,14 +15,14 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import Any
|
|
18
|
+
from typing import Any
|
|
19
19
|
|
|
20
|
-
from pydantic import
|
|
20
|
+
from pydantic import field_validator
|
|
21
21
|
|
|
22
22
|
from dara.components.common.base_component import FormComponent
|
|
23
23
|
from dara.components.common.utils import Item
|
|
24
24
|
from dara.core.base_definitions import Action
|
|
25
|
-
from dara.core.interactivity import
|
|
25
|
+
from dara.core.interactivity import ClientVariable, Variable
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
class CheckboxGroup(FormComponent):
|
|
@@ -37,7 +37,7 @@ class CheckboxGroup(FormComponent):
|
|
|
37
37
|
|
|
38
38
|
```python
|
|
39
39
|
from dara.core import Variable
|
|
40
|
-
from dara.components
|
|
40
|
+
from dara.components import CheckboxGroup
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
CheckboxGroup(
|
|
@@ -46,17 +46,26 @@ class CheckboxGroup(FormComponent):
|
|
|
46
46
|
)
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
CheckboxGroup
|
|
49
|
+
CheckboxGroup with items with custom labels and values:
|
|
50
50
|
|
|
51
51
|
```python
|
|
52
52
|
from dara.core import Variable
|
|
53
|
-
from dara.components
|
|
53
|
+
from dara.components import CheckboxGroup, Item
|
|
54
54
|
|
|
55
|
-
|
|
55
|
+
CheckboxGroup(
|
|
56
|
+
items=[Item(label='first',value=1), Item(label='second',value=2)],
|
|
57
|
+
value=Variable([1]),
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
CheckboxGroup component with at most two values selectable at a time:
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from dara.core import Variable
|
|
65
|
+
from dara.components import CheckboxGroup
|
|
56
66
|
|
|
57
67
|
CheckboxGroup(
|
|
58
68
|
items=['first', 'second', 'third', 'fourth', 'fifth'],
|
|
59
|
-
onchange=var_to_update.sync(),
|
|
60
69
|
value=Variable(),
|
|
61
70
|
select_max=2,
|
|
62
71
|
)
|
|
@@ -69,11 +78,9 @@ class CheckboxGroup(FormComponent):
|
|
|
69
78
|
from dara.components.common import CheckboxGroup
|
|
70
79
|
|
|
71
80
|
var = Variable()
|
|
72
|
-
var_to_update = Variable()
|
|
73
81
|
|
|
74
82
|
CheckboxGroup(
|
|
75
83
|
items=['first', 'second', 'third', 'fourth', 'fifth'],
|
|
76
|
-
onchange=var_to_update.sync(),
|
|
77
84
|
value=var,
|
|
78
85
|
select_min=2,
|
|
79
86
|
list_styling=True,
|
|
@@ -90,18 +97,18 @@ class CheckboxGroup(FormComponent):
|
|
|
90
97
|
:param id: the key to be used if this component is within a form
|
|
91
98
|
"""
|
|
92
99
|
|
|
93
|
-
items:
|
|
94
|
-
select_max:
|
|
95
|
-
select_min:
|
|
100
|
+
items: list[Item] | ClientVariable
|
|
101
|
+
select_max: int | None = None
|
|
102
|
+
select_min: int | None = None
|
|
96
103
|
list_styling: bool = False
|
|
97
|
-
value:
|
|
98
|
-
onchange:
|
|
99
|
-
id:
|
|
104
|
+
value: Variable[Any] | None = None
|
|
105
|
+
onchange: Action | None = None
|
|
106
|
+
id: str | None = None
|
|
100
107
|
|
|
101
|
-
@
|
|
108
|
+
@field_validator('items', mode='before')
|
|
102
109
|
@classmethod
|
|
103
|
-
def validate_items(cls, items: Any) ->
|
|
104
|
-
if isinstance(items,
|
|
110
|
+
def validate_items(cls, items: Any) -> list[Item] | ClientVariable:
|
|
111
|
+
if isinstance(items, ClientVariable):
|
|
105
112
|
return items
|
|
106
113
|
if not isinstance(items, list):
|
|
107
114
|
raise ValueError('Items must be passed as a list to the CheckboxGroup component')
|
dara/components/common/code.py
CHANGED
|
@@ -16,10 +16,10 @@ limitations under the License.
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
from enum import Enum
|
|
19
|
-
from typing import
|
|
19
|
+
from typing import ClassVar
|
|
20
20
|
|
|
21
21
|
from dara.components.common.base_component import ContentComponent
|
|
22
|
-
from dara.core.interactivity import
|
|
22
|
+
from dara.core.interactivity import ClientVariable
|
|
23
23
|
|
|
24
24
|
|
|
25
25
|
class Themes(str, Enum):
|
|
@@ -29,6 +29,9 @@ class Themes(str, Enum):
|
|
|
29
29
|
DARK = 'dark'
|
|
30
30
|
|
|
31
31
|
|
|
32
|
+
ThemesType = type[Themes]
|
|
33
|
+
|
|
34
|
+
|
|
32
35
|
class Code(ContentComponent):
|
|
33
36
|
"""
|
|
34
37
|

|
|
@@ -64,8 +67,8 @@ class Code(ContentComponent):
|
|
|
64
67
|
:param language: The language to use for code highlighting
|
|
65
68
|
"""
|
|
66
69
|
|
|
67
|
-
code:
|
|
68
|
-
theme:
|
|
70
|
+
code: str | ClientVariable
|
|
71
|
+
theme: Themes | None = None
|
|
69
72
|
language: str = 'python'
|
|
70
73
|
|
|
71
|
-
Themes = Themes
|
|
74
|
+
Themes: ClassVar[ThemesType] = Themes
|
|
@@ -15,23 +15,19 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import List, Optional, Union
|
|
19
|
-
|
|
20
|
-
from pydantic import BaseModel
|
|
21
|
-
|
|
22
18
|
from dara.components.common.base_component import LayoutComponent
|
|
23
19
|
from dara.core.base_definitions import Action
|
|
20
|
+
from dara.core.base_definitions import DaraBaseModel as BaseModel
|
|
24
21
|
from dara.core.definitions import ComponentInstanceType
|
|
25
22
|
from dara.core.interactivity import Variable
|
|
26
23
|
|
|
27
24
|
|
|
28
25
|
class ComponentItem(BaseModel):
|
|
29
26
|
title: str
|
|
30
|
-
subtitle:
|
|
27
|
+
subtitle: str | None = None
|
|
31
28
|
component: ComponentInstanceType
|
|
32
29
|
|
|
33
30
|
|
|
34
|
-
# TODO: update docs with examples once component is fixed
|
|
35
31
|
class ComponentSelectList(LayoutComponent):
|
|
36
32
|
"""
|
|
37
33
|

|
|
@@ -41,11 +37,11 @@ class ComponentSelectList(LayoutComponent):
|
|
|
41
37
|
A ComponentSelectList can be created via:
|
|
42
38
|
```python
|
|
43
39
|
from dara.core import Variable
|
|
44
|
-
from dara.components
|
|
40
|
+
from dara.components import (
|
|
45
41
|
ComponentSelectList,
|
|
42
|
+
ComponentItem,
|
|
46
43
|
Text,
|
|
47
44
|
)
|
|
48
|
-
from dara.components.common.component_select_list.component_select_list import ComponentItem
|
|
49
45
|
|
|
50
46
|
ComponentSelectList(
|
|
51
47
|
items=[
|
|
@@ -64,8 +60,8 @@ class ComponentSelectList(LayoutComponent):
|
|
|
64
60
|
:param selected_items: The initial selected items, can be an list if multiSelect is true otherwise a string. This takes the titles of the items as value.
|
|
65
61
|
"""
|
|
66
62
|
|
|
67
|
-
items:
|
|
68
|
-
items_per_row:
|
|
69
|
-
multi_select:
|
|
70
|
-
on_select:
|
|
71
|
-
selected_items:
|
|
63
|
+
items: list[ComponentItem]
|
|
64
|
+
items_per_row: int | None = None
|
|
65
|
+
multi_select: bool | None = None
|
|
66
|
+
on_select: Action | None = None
|
|
67
|
+
selected_items: Variable[str | list[str]] | None = None
|
|
@@ -16,11 +16,11 @@ limitations under the License.
|
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
18
|
from datetime import datetime
|
|
19
|
-
from typing import Any
|
|
19
|
+
from typing import Any
|
|
20
20
|
|
|
21
21
|
from dara.components.common.base_component import FormComponent
|
|
22
22
|
from dara.core.base_definitions import Action
|
|
23
|
-
from dara.core.interactivity import
|
|
23
|
+
from dara.core.interactivity import Variable
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class Datepicker(FormComponent):
|
|
@@ -37,48 +37,48 @@ class Datepicker(FormComponent):
|
|
|
37
37
|
A single Datepicker component that tracks the chosen value is created via:
|
|
38
38
|
|
|
39
39
|
```python
|
|
40
|
-
|
|
41
40
|
from dara.core import Variable
|
|
42
41
|
from dara.components.common import Datepicker
|
|
43
42
|
|
|
43
|
+
date_var = Variable()
|
|
44
|
+
|
|
44
45
|
Datepicker(
|
|
45
|
-
value=
|
|
46
|
+
value=date_var
|
|
46
47
|
)
|
|
47
|
-
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
A Datepicker component that allows to choose between a date range is created via:
|
|
51
51
|
|
|
52
52
|
```python
|
|
53
|
-
|
|
54
53
|
from dara.core import Variable
|
|
55
54
|
from dara.components.common import Datepicker
|
|
56
55
|
|
|
56
|
+
date_var = Variable()
|
|
57
|
+
|
|
57
58
|
Datepicker(
|
|
58
|
-
value=
|
|
59
|
+
value=date_var,
|
|
59
60
|
range=True,
|
|
60
61
|
)
|
|
61
|
-
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
A more complicated example with an initial date, has a custom
|
|
65
65
|
format, and does not close on selection is created via:
|
|
66
66
|
|
|
67
67
|
```python
|
|
68
|
-
|
|
69
68
|
from datetime import datetime
|
|
70
69
|
from dara.core import Variable
|
|
71
70
|
from dara.components.common import Datepicker
|
|
72
71
|
|
|
72
|
+
date_var = Variable(datetime(2021, 9, 18))
|
|
73
|
+
|
|
73
74
|
Datepicker(
|
|
74
|
-
value=
|
|
75
|
+
value=date_var,
|
|
75
76
|
date_format='MM/dd/yyyy',
|
|
76
77
|
enable_time=True,
|
|
77
78
|
max_date=datetime(2023, 12, 21),
|
|
78
79
|
min_date=datetime(2020, 3, 20),
|
|
79
80
|
select_close=False,
|
|
80
81
|
),
|
|
81
|
-
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
:param value: A Variable with the initial date value
|
|
@@ -93,12 +93,12 @@ class Datepicker(FormComponent):
|
|
|
93
93
|
:param id: the key to be used if this component is within a form
|
|
94
94
|
"""
|
|
95
95
|
|
|
96
|
-
value:
|
|
96
|
+
value: Variable[Any] | None = None
|
|
97
97
|
date_format: str = 'dd/MM/yyyy'
|
|
98
98
|
enable_time: bool = False
|
|
99
|
-
max_date:
|
|
100
|
-
min_date:
|
|
99
|
+
max_date: datetime | None = None
|
|
100
|
+
min_date: datetime | None = None
|
|
101
101
|
range: bool = False
|
|
102
102
|
select_close: bool = True
|
|
103
|
-
onchange:
|
|
104
|
-
id:
|
|
103
|
+
onchange: Action | None = None
|
|
104
|
+
id: str | None = None
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from typing_extensions import TypedDict
|
|
4
|
+
|
|
5
|
+
from dara.components.common.base_component import BaseDashboardComponent
|
|
6
|
+
from dara.components.common.button import Button
|
|
7
|
+
from dara.core import Action, ClientVariable, ComponentInstance
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class MenuItem(TypedDict, total=False):
|
|
11
|
+
label: str | ComponentInstance
|
|
12
|
+
"""the label of the menu item"""
|
|
13
|
+
|
|
14
|
+
icon: str | None
|
|
15
|
+
"""optional icon to show next to the label, use get_icon() helper"""
|
|
16
|
+
|
|
17
|
+
style: dict[str, Any] | None
|
|
18
|
+
"""optional style to apply to the menu item"""
|
|
19
|
+
|
|
20
|
+
prevent_close: bool | None
|
|
21
|
+
"""optional flag to prevent the menu from closing when the item is clicked"""
|
|
22
|
+
|
|
23
|
+
before: ComponentInstance | None
|
|
24
|
+
"""optional component to show before the label"""
|
|
25
|
+
|
|
26
|
+
after: ComponentInstance | None
|
|
27
|
+
"""optional component to show after the label"""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class DropdownMenu(BaseDashboardComponent):
|
|
31
|
+
"""
|
|
32
|
+
A DropdownMenu component that displays a button which opens a dropdown menu with configurable menu items.
|
|
33
|
+
Menu items can be organized into sections and support icons, custom styling, and custom components.
|
|
34
|
+
|
|
35
|
+
A basic dropdown menu with simple text items:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from dara.core import action, ActionCtx
|
|
39
|
+
from dara.components import Button, DropdownMenu
|
|
40
|
+
|
|
41
|
+
@action
|
|
42
|
+
async def handle_menu_click(ctx: ActionCtx):
|
|
43
|
+
print(f"Clicked: {ctx.input['label']}")
|
|
44
|
+
|
|
45
|
+
DropdownMenu(
|
|
46
|
+
button=Button('Options'),
|
|
47
|
+
onclick=handle_menu_click(),
|
|
48
|
+
menu_items=[
|
|
49
|
+
[
|
|
50
|
+
MenuItem(label='Edit'),
|
|
51
|
+
MenuItem(label='Delete'),
|
|
52
|
+
]
|
|
53
|
+
]
|
|
54
|
+
)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A dropdown menu with icons and custom styling:
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
from dara.core import action, ActionCtx, get_icon
|
|
61
|
+
from dara.components import Button, DropdownMenu
|
|
62
|
+
|
|
63
|
+
@action
|
|
64
|
+
async def handle_menu_click(ctx: ActionCtx):
|
|
65
|
+
print(f"Clicked: {ctx.input['label']}")
|
|
66
|
+
|
|
67
|
+
DropdownMenu(
|
|
68
|
+
button=Button('Actions', icon=get_icon('chevron-down')),
|
|
69
|
+
onclick=handle_menu_click(),
|
|
70
|
+
menu_items=[
|
|
71
|
+
[
|
|
72
|
+
MenuItem(
|
|
73
|
+
label='Edit',
|
|
74
|
+
icon=get_icon('pen'),
|
|
75
|
+
style={'color': 'blue'}
|
|
76
|
+
),
|
|
77
|
+
MenuItem(
|
|
78
|
+
label='Delete',
|
|
79
|
+
icon=get_icon('trash'),
|
|
80
|
+
style={'color': 'red'}
|
|
81
|
+
),
|
|
82
|
+
],
|
|
83
|
+
[
|
|
84
|
+
MenuItem(label='Settings', icon=get_icon('gear'))
|
|
85
|
+
]
|
|
86
|
+
]
|
|
87
|
+
)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
A dropdown menu with custom components and prevent close behavior:
|
|
91
|
+
|
|
92
|
+
```python
|
|
93
|
+
from dara.core import action, ActionCtx, Variable
|
|
94
|
+
from dara.components import Button, DropdownMenu, Text, Stack
|
|
95
|
+
|
|
96
|
+
counter = Variable(0)
|
|
97
|
+
|
|
98
|
+
@action
|
|
99
|
+
async def handle_menu_click(ctx: ActionCtx, counter_value: int):
|
|
100
|
+
print(f"Clicked: {ctx.input['label']}")
|
|
101
|
+
|
|
102
|
+
if ctx.input['label'] == 'Increment':
|
|
103
|
+
await ctx.update(counter, counter_value + 1)
|
|
104
|
+
|
|
105
|
+
DropdownMenu(
|
|
106
|
+
button=Button('Custom Menu'),
|
|
107
|
+
onclick=handle_menu_click(counter),
|
|
108
|
+
menu_items=[
|
|
109
|
+
[
|
|
110
|
+
MenuItem(
|
|
111
|
+
label=Stack(Text('Counter: '), Text(counter)),
|
|
112
|
+
prevent_close=True
|
|
113
|
+
),
|
|
114
|
+
MenuItem(
|
|
115
|
+
label='Increment',
|
|
116
|
+
before=Text('→'),
|
|
117
|
+
after=Text('↑')
|
|
118
|
+
)
|
|
119
|
+
]
|
|
120
|
+
]
|
|
121
|
+
)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
A dropdown menu with footer content at the bottom:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
from dara.core import action, ActionCtx
|
|
128
|
+
from dara.components import Button, DropdownMenu, Text, Stack
|
|
129
|
+
|
|
130
|
+
@action
|
|
131
|
+
async def handle_menu_click(ctx: ActionCtx):
|
|
132
|
+
print(f"Clicked: {ctx.input['label']}")
|
|
133
|
+
|
|
134
|
+
DropdownMenu(
|
|
135
|
+
button=Button('Menu with Footer'),
|
|
136
|
+
onclick=handle_menu_click(),
|
|
137
|
+
menu_items=[
|
|
138
|
+
[
|
|
139
|
+
MenuItem(label='Option 1'),
|
|
140
|
+
MenuItem(label='Option 2'),
|
|
141
|
+
]
|
|
142
|
+
],
|
|
143
|
+
footer=Stack(
|
|
144
|
+
Text(
|
|
145
|
+
'Additional info or controls can go here',
|
|
146
|
+
raw_css={'padding': '8px', 'font-size': '0.8rem', 'color': 'gray'},
|
|
147
|
+
)
|
|
148
|
+
)
|
|
149
|
+
)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
:param button: The button component that triggers the dropdown menu
|
|
153
|
+
:param onclick: Action triggered when a menu item is clicked, receives the clicked item as parameter
|
|
154
|
+
:param menu_items: List of menu item sections, where each section is a list of MenuItem objects
|
|
155
|
+
:param footer: Optional component to display at the bottom of the dropdown menu
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
button: Button
|
|
159
|
+
onclick: Action
|
|
160
|
+
menu_items: list[list[MenuItem]] | ClientVariable
|
|
161
|
+
footer: ComponentInstance | None = None
|
|
@@ -15,62 +15,71 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from
|
|
18
|
+
from collections.abc import Callable
|
|
19
19
|
from uuid import uuid4
|
|
20
20
|
|
|
21
21
|
from pandas import DataFrame
|
|
22
|
+
from pydantic import ConfigDict
|
|
22
23
|
|
|
23
24
|
from dara.core.base_definitions import Action, UploadResolverDef
|
|
24
25
|
from dara.core.definitions import StyledComponentInstance
|
|
25
|
-
from dara.core.interactivity import
|
|
26
|
+
from dara.core.interactivity import ServerVariable
|
|
26
27
|
|
|
27
|
-
DropzoneResolver =
|
|
28
|
-
Callable[[bytes, str], DataFrame],
|
|
29
|
-
Callable[[bytes, str], None],
|
|
30
|
-
]
|
|
28
|
+
DropzoneResolver = Callable[[bytes, str], DataFrame] | Callable[[bytes, str], None]
|
|
31
29
|
|
|
32
30
|
|
|
33
31
|
class UploadDropzone(StyledComponentInstance):
|
|
34
32
|
"""
|
|
35
|
-
|
|
33
|
+

|
|
34
|
+
|
|
35
|
+
A component that exposes a dropzone for uploading files. Takes a ServerVariable instance
|
|
36
36
|
that will store the dataset uploaded and an on_drop action that is triggered when
|
|
37
37
|
a file is successfully uploaded after being dropped or pasted.
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import os
|
|
41
|
+
from dara.components import UploadDropzone
|
|
42
|
+
|
|
43
|
+
def handle_file_uploaded(file_data: bytes, file_name: str):
|
|
44
|
+
os.makedirs('data', exist_ok=True)
|
|
45
|
+
with open(os.path.join('data', file_name), 'wb') as f:
|
|
46
|
+
f.write(file_data)
|
|
47
|
+
|
|
48
|
+
UploadDropzone(
|
|
49
|
+
accept="image/png, image/jpeg",
|
|
50
|
+
resolver=handle_file_uploaded
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
:param accept: optional comma-separated list of MIME-types or filename extensions accepted by the frontend; see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers for detail.
|
|
55
|
+
When not specified, defaults to accepting csv/xlsx; more specifically: `.csv, text/csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, application/csv, text/x-csv, application/x-csv, text/comma-separated-values, text/x-comma-separated-values`
|
|
56
|
+
:param target: server variable storing the data
|
|
57
|
+
:param resolver: optional resolver accepting `bytes` and filename as a string
|
|
58
|
+
- if a target is specified, can be used to customise how the `bytes` received are turned into a `DataFrame`
|
|
59
|
+
- if a target is not specified, can be treated as a side effect function to run on the `bytes` received (to i.e. store on disk)
|
|
60
|
+
:param on_drop: optional action triggered when a file is successfully uploaded
|
|
61
|
+
:param enable_paste: determines if the component should listen for and handle paste events (e.g., CTRL+V or right-click and paste). When set to True, the component allows text to be pasted directly, creating a file from the pasted content. This feature is disabled by default to accommodate scenarios where pasting text is not intended or could interfere with the component's primary functionality.
|
|
38
62
|
"""
|
|
39
63
|
|
|
40
64
|
js_module = '@darajs/components'
|
|
41
65
|
|
|
42
|
-
accept:
|
|
43
|
-
target:
|
|
44
|
-
resolver:
|
|
45
|
-
on_drop:
|
|
66
|
+
accept: str | None = None
|
|
67
|
+
target: ServerVariable | None = None
|
|
68
|
+
resolver: DropzoneResolver | None = None
|
|
69
|
+
on_drop: Action | None = None
|
|
46
70
|
enable_paste: bool = False
|
|
47
71
|
|
|
48
|
-
|
|
49
|
-
extra = 'allow'
|
|
72
|
+
model_config = ConfigDict(extra='allow')
|
|
50
73
|
|
|
51
74
|
def __init__(
|
|
52
75
|
self,
|
|
53
|
-
target:
|
|
54
|
-
resolver:
|
|
55
|
-
on_drop:
|
|
56
|
-
accept:
|
|
57
|
-
enable_paste:
|
|
58
|
-
**kwargs
|
|
76
|
+
target: ServerVariable | None = None,
|
|
77
|
+
resolver: DropzoneResolver | None = None,
|
|
78
|
+
on_drop: Action | None = None,
|
|
79
|
+
accept: str | None = None,
|
|
80
|
+
enable_paste: bool | None = False,
|
|
81
|
+
**kwargs,
|
|
59
82
|
):
|
|
60
|
-
"""
|
|
61
|
-
A component that exposes a dropzone for uploading files. Takes a DataVariable instance
|
|
62
|
-
that will store the dataset uploaded and an on_drop action that is triggered when
|
|
63
|
-
a file is successfully uploaded after being dropped or pasted.
|
|
64
|
-
|
|
65
|
-
:param accept: optional comma-separated list of MIME-types or filename extensions accepted by the frontend; see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/file#unique_file_type_specifiers for detail.
|
|
66
|
-
When not specified, defaults to accepting csv/xlsx; more specifically: `.csv, text/csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel, application/csv, text/x-csv, application/x-csv, text/comma-separated-values, text/x-comma-separated-values`
|
|
67
|
-
:param target: data variable storing the data
|
|
68
|
-
:param resolver: optional resolver accepting `bytes` and filename as a string
|
|
69
|
-
- if a target is specified, can be used to customise how the `bytes` received are turned into a `DataFrame`
|
|
70
|
-
- if a target is not specified, can be treated as a side effect function to run on the `bytes` received (to i.e. store on disk)
|
|
71
|
-
:param on_drop: optional action triggered when a file is successfully uploaded
|
|
72
|
-
:param enable_paste: determines if the component should listen for and handle paste events (e.g., CTRL+V or right-click and paste). When set to True, the component allows text to be pasted directly, creating a file from the pasted content. This feature is disabled by default to accommodate scenarios where pasting text is not intended or could interfere with the component's primary functionality.
|
|
73
|
-
"""
|
|
74
83
|
from dara.core.interactivity.any_data_variable import upload
|
|
75
84
|
from dara.core.internal.registries import upload_resolver_registry
|
|
76
85
|
|
dara/components/common/form.py
CHANGED
|
@@ -15,9 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from pydantic import validator
|
|
18
|
+
from pydantic import field_validator
|
|
21
19
|
|
|
22
20
|
from dara.components.common.base_component import LayoutComponent
|
|
23
21
|
from dara.core.base_definitions import Action
|
|
@@ -82,12 +80,12 @@ class Form(LayoutComponent):
|
|
|
82
80
|
:param align: How to align the content of the form, accepts any flexbox alignments
|
|
83
81
|
"""
|
|
84
82
|
|
|
85
|
-
value:
|
|
86
|
-
onsubmit:
|
|
83
|
+
value: Variable[dict] | None = None
|
|
84
|
+
onsubmit: Action | None = None
|
|
87
85
|
|
|
88
|
-
@
|
|
86
|
+
@field_validator('children')
|
|
89
87
|
@classmethod
|
|
90
|
-
def validate_children_pages(cls, children:
|
|
88
|
+
def validate_children_pages(cls, children: list[ComponentInstance]) -> list[ComponentInstance]:
|
|
91
89
|
# Make sure if FormPage is included, non-pages are not direct children of the Form
|
|
92
90
|
page_found = False
|
|
93
91
|
non_page_found = False
|
|
@@ -15,9 +15,7 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from
|
|
19
|
-
|
|
20
|
-
from pydantic import validator
|
|
18
|
+
from pydantic import field_validator
|
|
21
19
|
|
|
22
20
|
from dara.components.common.base_component import FormComponent
|
|
23
21
|
from dara.core.definitions import ComponentInstance
|
|
@@ -50,11 +48,11 @@ class FormPage(FormComponent):
|
|
|
50
48
|
:param title: The title of the form page
|
|
51
49
|
"""
|
|
52
50
|
|
|
53
|
-
title:
|
|
51
|
+
title: str | None = None
|
|
54
52
|
|
|
55
|
-
@
|
|
53
|
+
@field_validator('children')
|
|
56
54
|
@classmethod
|
|
57
|
-
def validate_children(cls, children:
|
|
55
|
+
def validate_children(cls, children: list[ComponentInstance]) -> list[ComponentInstance]:
|
|
58
56
|
for c in children:
|
|
59
57
|
if isinstance(c, FormPage):
|
|
60
58
|
raise TypeError('FormPage detected inside another FormPage, nesting is disallowed')
|
dara/components/common/grid.py
CHANGED
|
@@ -15,21 +15,20 @@ See the License for the specific language governing permissions and
|
|
|
15
15
|
limitations under the License.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
from typing import
|
|
19
|
-
|
|
20
|
-
from pydantic import BaseModel
|
|
18
|
+
from typing import ClassVar
|
|
21
19
|
|
|
22
20
|
from dara.components.common.base_component import LayoutComponent
|
|
21
|
+
from dara.core.base_definitions import DaraBaseModel as BaseModel
|
|
23
22
|
from dara.core.definitions import ComponentInstance, discover
|
|
24
23
|
from dara.core.visual.components.types import Direction
|
|
25
24
|
|
|
26
25
|
|
|
27
26
|
class ScreenBreakpoints(BaseModel):
|
|
28
|
-
xs:
|
|
29
|
-
sm:
|
|
30
|
-
md:
|
|
31
|
-
lg:
|
|
32
|
-
xl:
|
|
27
|
+
xs: int | None = None
|
|
28
|
+
sm: int | None = None
|
|
29
|
+
md: int | None = None
|
|
30
|
+
lg: int | None = None
|
|
31
|
+
xl: int | None = None
|
|
33
32
|
|
|
34
33
|
|
|
35
34
|
class Column(LayoutComponent):
|
|
@@ -68,11 +67,11 @@ class Column(LayoutComponent):
|
|
|
68
67
|
|
|
69
68
|
# TODO: :param order: optional number denoting the order of priority of the columns, with 1 being first to appear, and 12 the last to be added.
|
|
70
69
|
|
|
71
|
-
span:
|
|
72
|
-
offset:
|
|
70
|
+
span: int | ScreenBreakpoints | None = None
|
|
71
|
+
offset: int | ScreenBreakpoints | None = None
|
|
73
72
|
direction: Direction = Direction.HORIZONTAL
|
|
74
73
|
|
|
75
|
-
def __init__(self, *args: ComponentInstance, **kwargs):
|
|
74
|
+
def __init__(self, *args: ComponentInstance | None, **kwargs):
|
|
76
75
|
super().__init__(*args, **kwargs)
|
|
77
76
|
|
|
78
77
|
|
|
@@ -100,12 +99,16 @@ class Row(LayoutComponent):
|
|
|
100
99
|
:param align: How to align the content of the row, accepts any flexbox alignments
|
|
101
100
|
"""
|
|
102
101
|
|
|
103
|
-
column_gap:
|
|
102
|
+
column_gap: int | None = None
|
|
104
103
|
|
|
105
|
-
def __init__(self, *args: ComponentInstance, **kwargs):
|
|
104
|
+
def __init__(self, *args: ComponentInstance | None, **kwargs):
|
|
106
105
|
super().__init__(*args, **kwargs)
|
|
107
106
|
|
|
108
107
|
|
|
108
|
+
ColumnType = type[Column]
|
|
109
|
+
RowType = type[Row]
|
|
110
|
+
|
|
111
|
+
|
|
109
112
|
@discover
|
|
110
113
|
class Grid(LayoutComponent):
|
|
111
114
|
"""
|
|
@@ -117,14 +120,14 @@ class Grid(LayoutComponent):
|
|
|
117
120
|
"""
|
|
118
121
|
|
|
119
122
|
row_gap: str = '0.75rem'
|
|
120
|
-
breakpoints:
|
|
123
|
+
breakpoints: ScreenBreakpoints | None = ScreenBreakpoints()
|
|
121
124
|
|
|
122
|
-
Column = Column
|
|
123
|
-
Row = Row
|
|
124
|
-
Breakpoints = ScreenBreakpoints
|
|
125
|
+
Column: ClassVar[ColumnType] = Column
|
|
126
|
+
Row: ClassVar[RowType] = Row
|
|
127
|
+
Breakpoints: ClassVar[type[ScreenBreakpoints]] = ScreenBreakpoints
|
|
125
128
|
|
|
126
129
|
# Dummy init that just passes through arguments to superclass, fixes Pylance complaining about types
|
|
127
|
-
def __init__(self, *args: ComponentInstance, **kwargs):
|
|
130
|
+
def __init__(self, *args: ComponentInstance | None, **kwargs):
|
|
128
131
|
"""
|
|
129
132
|
Grid Layout provides a flexbox grid with a twelve column system.
|
|
130
133
|
Rows will automatically calculate their widths and wrap on the page as needed.
|