nova-trame 0.19.0.dev7__py3-none-any.whl → 0.19.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.
@@ -69,6 +69,7 @@ class DataSelectorState(BaseModel, validate_assignment=True):
69
69
  instrument: str = Field(default="", title="Instrument")
70
70
  experiment: str = Field(default="", title="Experiment")
71
71
  directory: str = Field(default="")
72
+ extensions: List[str] = Field(default=[])
72
73
  prefix: str = Field(default="")
73
74
 
74
75
  @field_validator("experiment", mode="after")
@@ -101,10 +102,11 @@ class DataSelectorState(BaseModel, validate_assignment=True):
101
102
  class DataSelectorModel:
102
103
  """Manages file system interactions for the DataSelector widget."""
103
104
 
104
- def __init__(self, facility: str, instrument: str, prefix: str) -> None:
105
+ def __init__(self, facility: str, instrument: str, extensions: List[str], prefix: str) -> None:
105
106
  self.state = DataSelectorState()
106
107
  self.state.facility = facility
107
108
  self.state.instrument = instrument
109
+ self.state.extensions = extensions
108
110
  self.state.prefix = prefix
109
111
 
110
112
  def get_facilities(self) -> List[str]:
@@ -192,7 +194,12 @@ class DataSelectorModel:
192
194
 
193
195
  for entry in os.scandir(datafile_path):
194
196
  if entry.is_file():
195
- datafiles.append(entry.path)
197
+ if self.state.extensions:
198
+ for extension in self.state.extensions:
199
+ if entry.path.lower().endswith(extension):
200
+ datafiles.append(entry.path)
201
+ else:
202
+ datafiles.append(entry.path)
196
203
  except OSError:
197
204
  pass
198
205
 
@@ -1,9 +1,9 @@
1
1
  """View Implementation for DataSelector."""
2
2
 
3
- from typing import Any, Optional, cast
3
+ from typing import Any, List, Optional, cast
4
4
 
5
5
  from trame.app import get_server
6
- from trame.widgets import html
6
+ from trame.widgets import client, html
7
7
  from trame.widgets import vuetify3 as vuetify
8
8
 
9
9
  from nova.mvvm.trame_binding import TrameBinding
@@ -16,7 +16,7 @@ from .input_field import InputField
16
16
  vuetify.enable_lab()
17
17
 
18
18
 
19
- class DataSelector(vuetify.VDataTable):
19
+ class DataSelector(vuetify.VDataTableVirtual):
20
20
  """Allows the user to select datafiles from an IPTS experiment."""
21
21
 
22
22
  def __init__(
@@ -24,6 +24,7 @@ class DataSelector(vuetify.VDataTable):
24
24
  v_model: str,
25
25
  facility: str = "",
26
26
  instrument: str = "",
27
+ extensions: Optional[List[str]] = None,
27
28
  prefix: str = "",
28
29
  select_strategy: str = "all",
29
30
  **kwargs: Any,
@@ -39,6 +40,8 @@ class DataSelector(vuetify.VDataTable):
39
40
  The facility to restrict data selection to. Options: HFIR, SNS
40
41
  instrument : str, optional
41
42
  The instrument to restrict data selection to. Please use the instrument acronym (e.g. CG-2).
43
+ extensions : List[str], optional
44
+ A list of file extensions to restrict selection to. If unset, then all files will be shown.
42
45
  prefix : str, optional
43
46
  A subdirectory within the user's chosen experiment to show files. If not specified, the user will be shown a
44
47
  folder browser and will be able to see all files in the experiment that they have access to.
@@ -62,6 +65,7 @@ class DataSelector(vuetify.VDataTable):
62
65
  self._label = None
63
66
 
64
67
  self._v_model = v_model
68
+ self._extensions = extensions if extensions is not None else []
65
69
  self._prefix = prefix
66
70
  self._select_strategy = select_strategy
67
71
 
@@ -72,6 +76,9 @@ class DataSelector(vuetify.VDataTable):
72
76
  self._directories_name = f"nova__dataselector_{self._next_id}_directories"
73
77
  self._datafiles_name = f"nova__dataselector_{self._next_id}_datafiles"
74
78
 
79
+ self._flush_state = f"flushState('{self._v_model.split('.')[0]}');"
80
+ self._reset_state = client.JSEval(exec=f"{self._v_model} = []; {self._flush_state}").exec
81
+
75
82
  self.create_model(facility, instrument)
76
83
  self.create_viewmodel()
77
84
 
@@ -98,7 +105,7 @@ class DataSelector(vuetify.VDataTable):
98
105
  type="autocomplete",
99
106
  )
100
107
 
101
- with GridLayout(columns=2, classes="flex-1-0", valign="start"):
108
+ with GridLayout(columns=2, classes="flex-1-0 h-0", valign="start"):
102
109
  if not self._prefix:
103
110
  with html.Div(classes="d-flex flex-column h-100 overflow-hidden"):
104
111
  vuetify.VListSubheader("Available Directories", classes="flex-0-1 justify-center px-0")
@@ -115,7 +122,8 @@ class DataSelector(vuetify.VDataTable):
115
122
 
116
123
  super().__init__(
117
124
  v_model=self._v_model,
118
- classes="overflow-y-auto",
125
+ classes="h-100 overflow-y-auto",
126
+ fixed_header=True,
119
127
  headers=("[{ align: 'left', key: 'title', title: 'Available Datafiles' }]",),
120
128
  item_title="title",
121
129
  item_value="path",
@@ -127,7 +135,7 @@ class DataSelector(vuetify.VDataTable):
127
135
  self.label = self._label
128
136
  self.items = (self._datafiles_name,)
129
137
  if "update_modelValue" not in kwargs:
130
- self.update_modelValue = f"flushState('{self._v_model.split('.')[0]}')"
138
+ self.update_modelValue = self._flush_state
131
139
 
132
140
  with cast(
133
141
  vuetify.VSelect,
@@ -137,7 +145,7 @@ class DataSelector(vuetify.VDataTable):
137
145
  clearable=True,
138
146
  readonly=True,
139
147
  type="select",
140
- click_clear=f"{self._v_model} = []; flushState('{self._v_model.split('.')[0]}');",
148
+ click_clear=self.reset,
141
149
  ),
142
150
  ):
143
151
  with vuetify.Template(raw_attrs=['v-slot:selection="{ item, index }"']):
@@ -147,7 +155,7 @@ class DataSelector(vuetify.VDataTable):
147
155
  )
148
156
 
149
157
  def create_model(self, facility: str, instrument: str) -> None:
150
- self._model = DataSelectorModel(facility, instrument, self._prefix)
158
+ self._model = DataSelectorModel(facility, instrument, self._extensions, self._prefix)
151
159
 
152
160
  def create_viewmodel(self) -> None:
153
161
  server = get_server(None, client_type="vue3")
@@ -160,9 +168,13 @@ class DataSelector(vuetify.VDataTable):
160
168
  self._vm.experiments_bind.connect(self._experiments_name)
161
169
  self._vm.directories_bind.connect(self._directories_name)
162
170
  self._vm.datafiles_bind.connect(self._datafiles_name)
171
+ self._vm.reset_bind.connect(self.reset)
163
172
 
164
173
  self._vm.update_view()
165
174
 
175
+ def reset(self, _: Any = None) -> None:
176
+ self._reset_state()
177
+
166
178
  def set_state(
167
179
  self, facility: Optional[str] = None, instrument: Optional[str] = None, experiment: Optional[str] = None
168
180
  ) -> None:
@@ -100,6 +100,10 @@ class RemoteFileInput:
100
100
  **self.input_props,
101
101
  ),
102
102
  ) as input:
103
+ if isinstance(input.classes, str):
104
+ input.classes += " nova-remote-file-input"
105
+ else:
106
+ input.classes = "nova-remote-file-input"
103
107
  self.vm.init_view()
104
108
 
105
109
  with vuetify.Template(v_slot_append=True):
@@ -110,13 +114,11 @@ class RemoteFileInput:
110
114
  v_model=self.vm.get_dialog_state_name(), activator="parent", **self.dialog_props
111
115
  ):
112
116
  with vuetify.VCard(classes="pa-4"):
113
- vuetify.VCardTitle(input.label)
114
117
  vuetify.VTextField(
115
118
  v_model=self.vm.get_filter_state_name(),
116
119
  classes="mb-4 px-4",
117
- label="Current Selection",
118
- __events=["change"],
119
- change=(self.vm.select_file, "[$event.target.value]"),
120
+ label=input.label,
121
+ variant="outlined",
120
122
  update_modelValue=(self.vm.filter_paths, "[$event]"),
121
123
  )
122
124
 
@@ -123,7 +123,8 @@ class MatplotlibFigure(matplotlib.Figure):
123
123
  with open(Path(css_path, fname)) as css_file:
124
124
  content = css_file.read()
125
125
  client.Style(content)
126
- client.Script(FigureManagerWebAgg.get_javascript())
126
+ js = FigureManagerWebAgg.get_javascript()
127
+ client.Script(js.replace("window.setTimeout(set_focus, 100);", "//"))
127
128
 
128
129
  MatplotlibFigure.mpl_initialized = True
129
130
 
@@ -5,6 +5,8 @@ from typing import Any, Optional, Union
5
5
  from trame.widgets import html
6
6
  from trame_client.widgets.core import AbstractElement
7
7
 
8
+ from .utils import merge_styles
9
+
8
10
 
9
11
  class GridLayout(html.Div):
10
12
  """Creates a grid with a specified number of columns."""
@@ -37,6 +39,9 @@ class GridLayout(html.Div):
37
39
  valign : optional[str]
38
40
  The vertical alignment of items in the grid. See `MDN
39
41
  <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>`__ for available options.
42
+ gap : optional[str]
43
+ The gap to place between items (works both horizontally and vertically). Can be any CSS gap value (e.g.
44
+ "4px" or "0.25em"). Defaults to no gap between items.
40
45
  kwargs : Any
41
46
  Additional keyword arguments to pass to html.Div.
42
47
 
@@ -65,9 +70,10 @@ class GridLayout(html.Div):
65
70
  classes = " ".join(classes)
66
71
  classes += " d-grid"
67
72
 
68
- style = self.get_root_styles(columns, height, width, halign, valign, gap) | kwargs.pop("style", {})
73
+ widget_style = self.get_root_styles(columns, height, width, halign, valign, gap)
74
+ user_style = kwargs.pop("style", {})
69
75
 
70
- super().__init__(classes=classes, style=style, **kwargs)
76
+ super().__init__(classes=classes, style=merge_styles(widget_style, user_style), **kwargs)
71
77
 
72
78
  def get_root_styles(
73
79
  self,
@@ -4,6 +4,8 @@ from typing import Any, Optional, Union
4
4
 
5
5
  from trame.widgets import html
6
6
 
7
+ from .utils import merge_styles
8
+
7
9
 
8
10
  class HBoxLayout(html.Div):
9
11
  """Creates an element that horizontally stacks its children."""
@@ -34,6 +36,12 @@ class HBoxLayout(html.Div):
34
36
  valign : optional[str]
35
37
  The vertical alignment of items in the grid. See `MDN
36
38
  <https://developer.mozilla.org/en-US/docs/Web/CSS/align-items>`__ for available options.
39
+ gap : optional[str]
40
+ The horizontal gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
41
+ gap between items.
42
+ vspace : optional[str]
43
+ The vertical gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
44
+ gap between items.
37
45
  kwargs : Any
38
46
  Additional keyword arguments to pass to html.Div.
39
47
 
@@ -53,9 +61,10 @@ class HBoxLayout(html.Div):
53
61
  classes = " ".join(classes)
54
62
  classes += " d-flex flex-row"
55
63
 
56
- style = self.get_root_styles(height, width, halign, valign, gap, vspace) | kwargs.pop("style", {})
64
+ widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
65
+ user_style = kwargs.pop("style", {})
57
66
 
58
- super().__init__(classes=classes, style=style, **kwargs)
67
+ super().__init__(classes=classes, style=merge_styles(widget_style, user_style), **kwargs)
59
68
 
60
69
  def get_root_styles(
61
70
  self,
@@ -0,0 +1,16 @@
1
+ """Utilities for our layout components."""
2
+
3
+ from typing import Dict, Union
4
+
5
+
6
+ def merge_styles(*styles: Union[Dict[str, str], str]) -> str:
7
+ result = ""
8
+
9
+ for style in styles:
10
+ if isinstance(style, dict):
11
+ for key, value in style.items():
12
+ result += f" {key}: {value};"
13
+ else:
14
+ result += f" {style};"
15
+
16
+ return result
@@ -4,6 +4,8 @@ from typing import Any, Optional, Union
4
4
 
5
5
  from trame.widgets import html
6
6
 
7
+ from .utils import merge_styles
8
+
7
9
 
8
10
  class VBoxLayout(html.Div):
9
11
  """Creates an element that vertically stacks its children."""
@@ -34,6 +36,12 @@ class VBoxLayout(html.Div):
34
36
  valign : optional[str]
35
37
  The vertical alignment of items in the grid. See `MDN
36
38
  <https://developer.mozilla.org/en-US/docs/Web/CSS/justify-items>`__ for available options.
39
+ gap : optional[str]
40
+ The horizontal gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
41
+ gap between items.
42
+ vspace : optional[str]
43
+ The vertical gap to place between items. Can be any CSS gap value (e.g. "4px" or "0.25em"). Defaults to no
44
+ gap between items.
37
45
  kwargs : Any
38
46
  Additional keyword arguments to pass to html.Div.
39
47
 
@@ -53,9 +61,10 @@ class VBoxLayout(html.Div):
53
61
  classes = " ".join(classes)
54
62
  classes += " d-flex flex-column"
55
63
 
56
- style = self.get_root_styles(height, width, halign, valign, gap, vspace) | kwargs.pop("style", {})
64
+ widget_style = self.get_root_styles(height, width, halign, valign, gap, vspace)
65
+ user_style = kwargs.pop("style", {})
57
66
 
58
- super().__init__(classes=classes, style=style, **kwargs)
67
+ super().__init__(classes=classes, style=merge_styles(widget_style, user_style), **kwargs)
59
68
 
60
69
  def get_root_styles(
61
70
  self,
@@ -12,16 +12,6 @@ html {
12
12
  box-shadow: none !important;
13
13
  }
14
14
 
15
- .v-tab.v-btn {
16
- height: 30px !important;
17
- min-width: fit-content !important;
18
- padding: 10px !important;
19
- }
20
-
21
- .v-checkbox .v-selection-control {
22
- min-height: 0px !important;
23
- }
24
-
25
15
  .mpl-message, .ui-dialog-titlebar {
26
16
  display: none !important;
27
17
  }
@@ -64,10 +54,20 @@ html {
64
54
  }
65
55
 
66
56
  .nova-data-selector {
57
+ .v-list-subheader__text {
58
+ color: black;
59
+ font-weight: 500;
60
+ }
61
+
67
62
  .v-list-item {
68
63
  padding-left: 0;
69
64
  }
70
65
 
66
+ .v-list-subheader__text,
67
+ .v-list-item-title {
68
+ font-size: 0.75rem !important;
69
+ }
70
+
71
71
  .v-data-table__td {
72
72
  max-width: 100px;
73
73
  overflow: hidden;
@@ -87,7 +87,7 @@ html {
87
87
  }
88
88
 
89
89
  .v-data-table {
90
- td {
90
+ th, td {
91
91
  vertical-align: middle;
92
92
  }
93
93
 
@@ -96,12 +96,30 @@ html {
96
96
  }
97
97
  }
98
98
 
99
+ .nova-remote-file-input {
100
+ .v-input__append {
101
+ margin-left: 0;
102
+ }
103
+
104
+ .v-btn {
105
+ height: 30px;
106
+ }
107
+ }
108
+
99
109
  .v-tab.v-btn {
100
110
  height: 30px !important;
101
111
  min-width: fit-content !important;
102
112
  padding: 10px !important;
103
113
  }
104
114
 
115
+ .v-container {
116
+ padding: 0px !important;
117
+ }
118
+
119
+ .v-checkbox .v-selection-control {
120
+ min-height: 0px !important;
121
+ }
122
+
105
123
  .v-card-title,
106
124
  .v-list-item-title,
107
125
  .v-toolbar-title {
@@ -56,8 +56,7 @@
56
56
  },
57
57
  "VFileInput": {
58
58
  "color": "primary",
59
- "prependIcon": false,
60
- "variant": "outlined"
59
+ "prependIcon": false
61
60
  },
62
61
  "VLabel": {
63
62
  "style": {
@@ -92,8 +91,7 @@
92
91
  "color": "primary"
93
92
  },
94
93
  "VSelect": {
95
- "color": "primary",
96
- "variant": "outlined"
94
+ "color": "primary"
97
95
  },
98
96
  "VSlider": {
99
97
  "color": "primary"
@@ -108,12 +106,10 @@
108
106
  "color": "primary"
109
107
  },
110
108
  "VTextarea": {
111
- "color": "primary",
112
- "variant": "outlined"
109
+ "color": "primary"
113
110
  },
114
111
  "VTextField": {
115
- "color": "primary",
116
- "variant": "outlined"
112
+ "color": "primary"
117
113
  },
118
114
  "VWindowItem": {
119
115
  "reverseTransition": "fade-transition",
@@ -171,6 +167,9 @@
171
167
  "VDataTable": {
172
168
  "density": "compact"
173
169
  },
170
+ "VDataTableVirtual": {
171
+ "density": "compact"
172
+ },
174
173
  "VFileInput": {
175
174
  "variant": "outlined"
176
175
  },
@@ -219,7 +219,6 @@ class ThemedApp:
219
219
 
220
220
  with vuetify.VList(width=200):
221
221
  vuetify.VListSubheader("Select Theme")
222
- vuetify.VDivider()
223
222
 
224
223
  for theme in self.vuetify_config.get("theme", {}).get("themes", {}).values():
225
224
  with vuetify.VListItem(click=partial(self.set_theme, theme["value"])):
@@ -1,7 +1,7 @@
1
1
  """View model implementation for the DataSelector widget."""
2
2
 
3
3
  import os
4
- from typing import Any, Optional
4
+ from typing import Any, Dict, Optional
5
5
 
6
6
  from nova.mvvm.interface import BindingInterface
7
7
  from nova.trame.model.data_selector import DataSelectorModel
@@ -13,14 +13,15 @@ class DataSelectorViewModel:
13
13
  def __init__(self, model: DataSelectorModel, binding: BindingInterface) -> None:
14
14
  self.model = model
15
15
 
16
- self.state_bind = binding.new_bind(self.model.state, callback_after_update=self.update_view)
16
+ self.state_bind = binding.new_bind(self.model.state, callback_after_update=self.on_state_updated)
17
17
  self.facilities_bind = binding.new_bind()
18
18
  self.instruments_bind = binding.new_bind()
19
19
  self.experiments_bind = binding.new_bind()
20
20
  self.directories_bind = binding.new_bind()
21
21
  self.datafiles_bind = binding.new_bind()
22
+ self.reset_bind = binding.new_bind()
22
23
 
23
- def set_directory(self, directory_path: str) -> None:
24
+ def set_directory(self, directory_path: str = "") -> None:
24
25
  self.model.set_directory(directory_path)
25
26
  self.update_view()
26
27
 
@@ -28,7 +29,20 @@ class DataSelectorViewModel:
28
29
  self.model.set_state(facility, instrument, experiment)
29
30
  self.update_view()
30
31
 
31
- def update_view(self, _: Any = None) -> None:
32
+ def on_state_updated(self, results: Dict[str, Any]) -> None:
33
+ for update in results.get("updated", []):
34
+ match update:
35
+ case "facility":
36
+ self.model.set_state(facility=None, instrument="", experiment="")
37
+ self.model.set_directory("")
38
+ self.reset_bind.update_in_view(None)
39
+ case "instrument":
40
+ self.model.set_state(facility=None, instrument=None, experiment="")
41
+ self.model.set_directory("")
42
+ self.reset_bind.update_in_view(None)
43
+ self.update_view()
44
+
45
+ def update_view(self) -> None:
32
46
  self.state_bind.update_in_view(self.model.state)
33
47
  self.facilities_bind.update_in_view(self.model.get_facilities())
34
48
  self.instruments_bind.update_in_view(self.model.get_instruments())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nova-trame
3
- Version: 0.19.0.dev7
3
+ Version: 0.19.1
4
4
  Summary: A Python Package for injecting curated themes and custom components into Trame applications
5
5
  License: MIT
6
6
  Keywords: NDIP,Python,Trame,Vuetify
@@ -1,32 +1,33 @@
1
1
  nova/__init__.py,sha256=ED6jHcYiuYpr_0vjGz0zx2lrrmJT9sDJCzIljoDfmlM,65
2
2
  nova/trame/__init__.py,sha256=gFrAg1qva5PIqR5TjvPzAxLx103IKipJLqp3XXvrQL8,59
3
- nova/trame/model/data_selector.py,sha256=6tH5E7PmPMc6Cc7utFqe7MUpKsUP15_2jU0plygeqn0,7168
3
+ nova/trame/model/data_selector.py,sha256=sCLU0YIMCccC1BH8dKZPmajaft6WgwuM_zOr3NPk2bg,7552
4
4
  nova/trame/model/remote_file_input.py,sha256=9KAf31ZHzpsh_aXUrNcF81Q5jvUZDWCzW1QATKls-Jk,3675
5
5
  nova/trame/view/components/__init__.py,sha256=u8yzshFp_TmuC1g9TRxKjy_BdGWMIzPQouI52hzcr2U,234
6
- nova/trame/view/components/data_selector.py,sha256=3-tlSFzCigMEZs-TwTZ_Ejx3Q69gxVeOJXIADuBkHN0,8270
6
+ nova/trame/view/components/data_selector.py,sha256=UFQriSH25wk3F4s6EnP5Dfrt3MFbisJTrzmRxH0ME8U,8831
7
7
  nova/trame/view/components/file_upload.py,sha256=7VcpfA6zmiqMDLkwVPlb35Tf0IUTBN1xsHpoUFnSr1w,3111
8
8
  nova/trame/view/components/input_field.py,sha256=Wf-WuYm9SmbHXYy1cvYy8zDWe5rhvLcUHmwqmBvqVxk,16074
9
- nova/trame/view/components/remote_file_input.py,sha256=MnsUttZaCy8vEpOmRqXMsWa6PiC-RTRb-hJnnH0rBZc,9644
9
+ nova/trame/view/components/remote_file_input.py,sha256=ByrBFj8svyWezcardCWrS_4Ag3fgTYNg_11lDW1FIA8,9669
10
10
  nova/trame/view/components/visualization/__init__.py,sha256=reqkkbhD5uSksHHlhVMy1qNUCwSekS5HlXk6wCREYxU,152
11
11
  nova/trame/view/components/visualization/interactive_2d_plot.py,sha256=foZCMoqbuahT5dtqIQvm8C4ZJcY9P211eJEcpQJltmM,3421
12
- nova/trame/view/components/visualization/matplotlib_figure.py,sha256=xxgEAE2boc-sIFEIsbJxQZQ5biBMBXT0U8Il5299VNc,11974
12
+ nova/trame/view/components/visualization/matplotlib_figure.py,sha256=0iWCXB8i7Tut1gA66hY9cGrhZPaHC7p-XdADDNy_UVY,12042
13
13
  nova/trame/view/layouts/__init__.py,sha256=cMrlB5YMUoK8EGB83b34UU0kPTVrH8AxsYvKRtpUNEc,141
14
- nova/trame/view/layouts/grid.py,sha256=CPutDeiJnLsKiG2mBtIDAnHJX-NJE92vhFiFyraV0R8,5220
15
- nova/trame/view/layouts/hbox.py,sha256=NE11FV0W7QKfqIdz4MUOTIWsgCr8jrJDtUCcgw1K0HM,3060
16
- nova/trame/view/layouts/vbox.py,sha256=HkWpU6LiqdZMwl9KRosvxX_4lAxgjiRS5q9acIBUyfE,3061
14
+ nova/trame/view/layouts/grid.py,sha256=BYoylq-VN1l55BXBWMJ_7zvHcQYmfOo811nzD72IBOQ,5522
15
+ nova/trame/view/layouts/hbox.py,sha256=qlOMp_iOropIkC9Jxa6D89b7OPv0pNvJ73tUEzddyhQ,3513
16
+ nova/trame/view/layouts/utils.py,sha256=Hg34VQWTG3yHBsgNvmfatR4J-uL3cko7UxSJpT-h3JI,376
17
+ nova/trame/view/layouts/vbox.py,sha256=hzhzPu99R2fAclMe-FwHZseJWk7iailZ31bKdGhi1hk,3514
17
18
  nova/trame/view/theme/__init__.py,sha256=70_marDlTigIcPEOGiJb2JTs-8b2sGM5SlY7XBPtBDM,54
18
- nova/trame/view/theme/assets/core_style.scss,sha256=kB33fiic0OcMJedYGQeIN2QssF5q9KQCAdKYIJnRM-4,2882
19
+ nova/trame/view/theme/assets/core_style.scss,sha256=kxm66OdHeSAW1_zWJXWpzBZ30hopI1cgLwyXrqdmf1I,3214
19
20
  nova/trame/view/theme/assets/favicon.png,sha256=Xbp1nUmhcBDeObjsebEbEAraPDZ_M163M_ZLtm5AbQc,1927
20
21
  nova/trame/view/theme/assets/js/delay_manager.js,sha256=vmb34DZ5YCQIlRW9Tf2M_uvJW6HFCmtlKZ5e_TPR8yg,536
21
22
  nova/trame/view/theme/assets/js/lodash.debounce.min.js,sha256=GLzlQH04WDUNYN7i39ttHHejSdu-CpAvfWgDgKDn-OY,4448
22
23
  nova/trame/view/theme/assets/js/lodash.throttle.min.js,sha256=9csqjX-M-LVGJnF3z4ha1R_36O5AfkFE8rPHkxmt3tE,4677
23
- nova/trame/view/theme/assets/vuetify_config.json,sha256=KKS50xguCxl3RtBT7xx_Xk6qyH2RO-ePAG9UBGloIBI,5656
24
- nova/trame/view/theme/theme.py,sha256=OFUtq1IWriFcDu-346J67ZrSES8IOI9PTY_4Vwg7bZQ,11820
24
+ nova/trame/view/theme/assets/vuetify_config.json,sha256=a0FSgpLYWGFlRGSMhMq61MyDFBEBwvz55G4qjkM08cs,5627
25
+ nova/trame/view/theme/theme.py,sha256=HUeuVfzEgeYW65W-LcvXzfYNRHu6aQibGwwgHGyh3OA,11765
25
26
  nova/trame/view/utilities/local_storage.py,sha256=vD8f2VZIpxhIKjZwEaD7siiPCTZO4cw9AfhwdawwYLY,3218
26
- nova/trame/view_model/data_selector.py,sha256=Bpkfjd78ZIkexHNF_aA9PfizRBzkeOuoSE7ZsBFcSOs,1749
27
+ nova/trame/view_model/data_selector.py,sha256=FM1Xe-f-gi1jVwA9nDf2KE1UDvsAvmMKlp78slIpX58,2418
27
28
  nova/trame/view_model/remote_file_input.py,sha256=ojEOJ8ZPkajpbAaZi9VLj7g-uBjhb8BMrTdMmwf_J6A,3367
28
- nova_trame-0.19.0.dev7.dist-info/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
29
- nova_trame-0.19.0.dev7.dist-info/METADATA,sha256=CIUfrKoM8j1mwV-zA2dJgkYFpzqy2LPYR8SG8c6oz80,1451
30
- nova_trame-0.19.0.dev7.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
31
- nova_trame-0.19.0.dev7.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
32
- nova_trame-0.19.0.dev7.dist-info/RECORD,,
29
+ nova_trame-0.19.1.dist-info/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
30
+ nova_trame-0.19.1.dist-info/METADATA,sha256=KAU_st5MU5BO6fNu45_wh3J-DP8QwKastiWR2cCRpnA,1446
31
+ nova_trame-0.19.1.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
32
+ nova_trame-0.19.1.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
33
+ nova_trame-0.19.1.dist-info/RECORD,,