nova-trame 0.18.0.dev1__py3-none-any.whl → 0.19.0.dev0__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.
@@ -3,58 +3,65 @@
3
3
  import os
4
4
  from pathlib import Path
5
5
  from typing import List, Optional
6
+ from warnings import warn
6
7
 
7
8
  from pydantic import BaseModel, Field, field_validator, model_validator
8
9
  from typing_extensions import Self
9
10
 
10
- FACILITIES = ["HFIR", "SNS"]
11
11
  INSTRUMENTS = {
12
- "HFIR": [
13
- "CG1A",
14
- "CG1B",
15
- "CG1D",
16
- "CG2",
17
- "CG3",
18
- "CG4B",
19
- "CG4C",
20
- "CG4D",
21
- "HB1",
22
- "HB1A",
23
- "HB2A",
24
- "HB2B",
25
- "HB2C",
26
- "HB3",
27
- "HB3A",
28
- "NOWG",
29
- "NOWV",
30
- ],
31
- "SNS": [
32
- "ARCS",
33
- "BL0",
34
- "BSS",
35
- "CNCS",
36
- "CORELLI",
37
- "EQSANS",
38
- "HYS",
39
- "LENS",
40
- "MANDI",
41
- "NOM",
42
- "NOWG",
43
- "NSE",
44
- "PG3",
45
- "REF_L",
46
- "REF_M",
47
- "SEQ",
48
- "SNAP",
49
- "TOPAZ",
50
- "USANS",
51
- "VENUS",
52
- "VIS",
53
- "VULCAN",
54
- ],
12
+ "HFIR": {
13
+ "CG-1A": "CG1A",
14
+ "CG-1B": "CG1B",
15
+ "CG-1D": "CG1D",
16
+ "CG-2": "CG2",
17
+ "CG-3": "CG3",
18
+ "CG-4B": "CG4B",
19
+ "CG-4C": "CG4C",
20
+ "CG-4D": "CG4D",
21
+ "HB-1": "HB1",
22
+ "HB-1A": "HB1A",
23
+ "HB-2A": "HB2A",
24
+ "HB-2B": "HB2B",
25
+ "HB-2C": "HB2C",
26
+ "HB-3": "HB3",
27
+ "HB-3A": "HB3A",
28
+ "NOW-G": "NOWG",
29
+ "NOW-V": "NOWV",
30
+ },
31
+ "SNS": {
32
+ "BL-18": "ARCS",
33
+ "BL-0": "BL0",
34
+ "BL-2": "BSS",
35
+ "BL-5": "CNCS",
36
+ "BL-9": "CORELLI",
37
+ "BL-6": "EQSANS",
38
+ "BL-14B": "HYS",
39
+ "BL-11B": "MANDI",
40
+ "BL-1B": "NOM",
41
+ "NOW-G": "NOWG",
42
+ "BL-15": "NSE",
43
+ "BL-11A": "PG3",
44
+ "BL-4B": "REF_L",
45
+ "BL-4A": "REF_M",
46
+ "BL-17": "SEQ",
47
+ "BL-3": "SNAP",
48
+ "BL-12": "TOPAZ",
49
+ "BL-1A": "USANS",
50
+ "BL-10": "VENUS",
51
+ "BL-16B": "VIS",
52
+ "BL-7": "VULCAN",
53
+ },
55
54
  }
56
55
 
57
56
 
57
+ def get_facilities() -> List[str]:
58
+ return list(INSTRUMENTS.keys())
59
+
60
+
61
+ def get_instruments(facility: str) -> List[str]:
62
+ return list(INSTRUMENTS.get(facility, {}).keys())
63
+
64
+
58
65
  class DataSelectorState(BaseModel, validate_assignment=True):
59
66
  """Selection state for identifying datafiles."""
60
67
 
@@ -71,10 +78,19 @@ class DataSelectorState(BaseModel, validate_assignment=True):
71
78
 
72
79
  @model_validator(mode="after")
73
80
  def validate_state(self) -> Self:
74
- if self.facility and self.facility not in FACILITIES:
75
- raise ValueError("facility could not be found")
76
- if self.instrument and self.instrument not in INSTRUMENTS.get(self.facility, []):
77
- raise ValueError(f"instrument could not be found in {self.facility}")
81
+ valid_facilities = get_facilities()
82
+ if self.facility and self.facility not in valid_facilities:
83
+ warn(f"Facility '{self.facility}' could not be found. Valid options: {valid_facilities}", stacklevel=1)
84
+
85
+ valid_instruments = get_instruments(self.facility)
86
+ if self.instrument and self.instrument not in valid_instruments:
87
+ warn(
88
+ (
89
+ f"Instrument '{self.instrument}' could not be found in '{self.facility}'. "
90
+ f"Valid options: {valid_instruments}"
91
+ ),
92
+ stacklevel=1,
93
+ )
78
94
  # Validating the experiment is expensive and will fail in our CI due to the filesystem not being mounted there.
79
95
 
80
96
  return self
@@ -89,35 +105,38 @@ class DataSelectorModel:
89
105
  self.state.instrument = instrument
90
106
 
91
107
  def get_facilities(self) -> List[str]:
92
- return FACILITIES
108
+ return get_facilities()
109
+
110
+ def get_instrument_dir(self) -> str:
111
+ return INSTRUMENTS.get(self.state.facility, {}).get(self.state.instrument, "")
93
112
 
94
113
  def get_instruments(self) -> List[str]:
95
- return INSTRUMENTS.get(self.state.facility, [])
114
+ return get_instruments(self.state.facility)
96
115
 
97
116
  def get_experiments(self) -> List[str]:
98
117
  experiments = []
99
118
 
100
- instrument_path = Path("/") / self.state.facility / self.state.instrument
119
+ instrument_path = Path("/") / self.state.facility / self.get_instrument_dir()
101
120
  try:
102
121
  for dirname in os.listdir(instrument_path):
103
- if dirname.startswith("IPTS-"):
122
+ if dirname.startswith("IPTS-") and os.access(instrument_path / dirname, mode=os.R_OK):
104
123
  experiments.append(dirname)
105
124
  except OSError:
106
125
  pass
107
126
 
108
- return experiments
127
+ return sorted(experiments)
109
128
 
110
129
  def get_datafiles(self) -> List[str]:
111
130
  datafiles = []
112
131
 
113
- experiment_path = Path("/") / self.state.facility / self.state.instrument / self.state.experiment / "nexus"
132
+ experiment_path = Path("/") / self.state.facility / self.get_instrument_dir() / self.state.experiment / "nexus"
114
133
  try:
115
134
  for fname in os.listdir(experiment_path):
116
135
  datafiles.append(str(experiment_path / fname))
117
136
  except OSError:
118
137
  pass
119
138
 
120
- return datafiles
139
+ return sorted(datafiles)
121
140
 
122
141
  def set_state(self, facility: Optional[str], instrument: Optional[str], experiment: Optional[str]) -> None:
123
142
  if facility is not None:
@@ -1,5 +1,6 @@
1
1
  from .data_selector import DataSelector
2
+ from .file_upload import FileUpload
2
3
  from .input_field import InputField
3
4
  from .remote_file_input import RemoteFileInput
4
5
 
5
- __all__ = ["DataSelector", "InputField", "RemoteFileInput"]
6
+ __all__ = ["DataSelector", "FileUpload", "InputField", "RemoteFileInput"]
@@ -7,27 +7,30 @@ from trame.widgets import vuetify3 as vuetify
7
7
 
8
8
  from nova.mvvm.trame_binding import TrameBinding
9
9
  from nova.trame.model.data_selector import DataSelectorModel
10
- from nova.trame.view.layouts import HBoxLayout
10
+ from nova.trame.view.layouts import GridLayout
11
11
  from nova.trame.view_model.data_selector import DataSelectorViewModel
12
12
 
13
13
  from .input_field import InputField
14
14
 
15
15
 
16
- class DataSelector(vuetify.VAutocomplete):
16
+ class DataSelector(vuetify.VDataTable):
17
17
  """Allows the user to select datafiles from an IPTS experiment."""
18
18
 
19
- def __init__(self, facility: str = "", instrument: str = "", **kwargs: Any) -> None:
19
+ def __init__(self, v_model: str, facility: str = "", instrument: str = "", **kwargs: Any) -> None:
20
20
  """Constructor for DataSelector.
21
21
 
22
22
  Parameters
23
23
  ----------
24
+ v_model : str
25
+ The name of the state variable to bind to this widget. The state variable will contain a list of the files
26
+ selected by the user.
24
27
  facility : str, optional
25
28
  The facility to restrict data selection to. Options: HFIR, SNS
26
29
  instrument : str, optional
27
- The instrument to restrict data selection to. Must be at the selected facility.
30
+ The instrument to restrict data selection to. Please use the instrument acronym (e.g. CG-2).
28
31
  **kwargs
29
32
  All other arguments will be passed to the underlying
30
- `Autocomplete component <https://trame.readthedocs.io/en/latest/trame.widgets.vuetify3.html#trame.widgets.vuetify3.VAutocomplete>`_.
33
+ `VDataTable component <https://trame.readthedocs.io/en/latest/trame.widgets.vuetify3.html#trame.widgets.vuetify3.VDataTable>`_.
31
34
 
32
35
  Returns
33
36
  -------
@@ -36,6 +39,7 @@ class DataSelector(vuetify.VAutocomplete):
36
39
  if "items" in kwargs:
37
40
  raise AttributeError("The items parameter is not allowed on DataSelector widget.")
38
41
 
42
+ self._v_model = v_model
39
43
  self._state_name = f"nova__dataselector_{self._next_id}_state"
40
44
  self._facilities_name = f"nova__dataselector_{self._next_id}_facilities"
41
45
  self._instruments_name = f"nova__dataselector_{self._next_id}_instruments"
@@ -48,18 +52,37 @@ class DataSelector(vuetify.VAutocomplete):
48
52
  self.create_ui(facility, instrument, **kwargs)
49
53
 
50
54
  def create_ui(self, facility: str, instrument: str, **kwargs: Any) -> None:
51
- with HBoxLayout(width="100%"):
55
+ with GridLayout(columns=3):
56
+ columns = 3
52
57
  if facility == "":
58
+ columns -= 1
53
59
  InputField(v_model=f"{self._state_name}.facility", items=(self._facilities_name,), type="autocomplete")
54
60
  if instrument == "":
61
+ columns -= 1
55
62
  InputField(
56
63
  v_model=f"{self._state_name}.instrument", items=(self._instruments_name,), type="autocomplete"
57
64
  )
58
- InputField(v_model=f"{self._state_name}.experiment", items=(self._experiments_name,), type="autocomplete")
59
-
60
- super().__init__(**kwargs)
65
+ InputField(
66
+ v_model=f"{self._state_name}.experiment",
67
+ column_span=columns,
68
+ items=(self._experiments_name,),
69
+ type="autocomplete",
70
+ )
71
+
72
+ super().__init__(
73
+ v_model=self._v_model,
74
+ column_span=3,
75
+ headers=("[{ align: 'center', key: 'file', title: 'Available Datafiles' }]",),
76
+ item_value="file",
77
+ select_strategy="all",
78
+ show_select=True,
79
+ **kwargs,
80
+ )
61
81
  self.items = (self._datafiles_name,)
62
82
 
83
+ if "update_modelValue" not in kwargs:
84
+ self.update_modelValue = f"flushState('{self._v_model.split('.')[0]}')"
85
+
63
86
  def create_model(self, facility: str, instrument: str) -> None:
64
87
  self._model = DataSelectorModel(facility, instrument)
65
88
 
@@ -0,0 +1,79 @@
1
+ """View implementation for FileUpload."""
2
+
3
+ from typing import Any, List, Optional
4
+
5
+ from trame.widgets import vuetify3 as vuetify
6
+
7
+ from .remote_file_input import RemoteFileInput
8
+
9
+
10
+ class FileUpload(vuetify.VBtn):
11
+ """Component for uploading a file from either the user's filesystem or the server filesystem."""
12
+
13
+ def __init__(
14
+ self, v_model: Optional[str] = None, base_paths: Optional[List[str]] = None, label: str = "", **kwargs: Any
15
+ ) -> None:
16
+ """Constructor for FileUpload.
17
+
18
+ Parameters
19
+ ----------
20
+ v_model : str, optional
21
+ The state variable to set when the user uploads their file. If uploaded from the user's machine, then the
22
+ state variable will contain a dictionary with the file contents and metadata. If uploaded from the server
23
+ filesystem, then the state variable will contain a path to the file.
24
+ base_paths: list[str], optional
25
+ Passed to :ref:`RemoteFileInput <api_remotefileinput>`.
26
+ label : str, optional
27
+ The text to display on the upload button.
28
+ **kwargs
29
+ All other arguments will be passed to the underlying
30
+ `Button component <https://trame.readthedocs.io/en/latest/trame.widgets.vuetify3.html#trame.widgets.vuetify3.VBtn>`_.
31
+
32
+ Returns
33
+ -------
34
+ None
35
+ """
36
+ self._v_model = v_model
37
+ if base_paths:
38
+ self._base_paths = base_paths
39
+ else:
40
+ self._base_paths = ["/"]
41
+ self._ref_name = f"nova__fileupload_{self._next_id}"
42
+
43
+ super().__init__(label, **kwargs)
44
+ self.create_ui()
45
+
46
+ def create_ui(self) -> None:
47
+ self.local_file_input = vuetify.VFileInput(v_model=(self._v_model, None), classes="d-none", ref=self._ref_name)
48
+ if self._v_model:
49
+ # Serialize the content in a way that will work with nova-mvvm and then push it to the server.
50
+ self.local_file_input.update_modelValue = (
51
+ f"{self._v_model}.text().then((contents) => {{ "
52
+ f" {self._v_model} = {{ contents: contents }};"
53
+ f" flushState('{self._v_model.split('.')[0]}');"
54
+ "});"
55
+ )
56
+ self.remote_file_input = RemoteFileInput(
57
+ v_model=self._v_model,
58
+ base_paths=self._base_paths,
59
+ input_props={"classes": "d-none"},
60
+ )
61
+ with self:
62
+ with vuetify.VMenu(activator="parent"):
63
+ with vuetify.VList():
64
+ vuetify.VListItem("From Local Machine", click=f"trame.refs.{self._ref_name}.click()")
65
+ vuetify.VListItem("From Analysis Cluster", click=self.remote_file_input.open_dialog)
66
+
67
+ def select_file(self, value: str) -> None:
68
+ """Programmatically set the RemoteFileInput path.
69
+
70
+ Parameters
71
+ ----------
72
+ value: str
73
+ The new value for the RemoteFileInput.
74
+
75
+ Returns
76
+ -------
77
+ None
78
+ """
79
+ self.remote_file_input.select_file(value)
@@ -10,9 +10,10 @@ from trame_client.widgets.core import AbstractElement
10
10
 
11
11
  from nova.mvvm.trame_binding import TrameBinding
12
12
  from nova.trame.model.remote_file_input import RemoteFileInputModel
13
- from nova.trame.view.components import InputField
14
13
  from nova.trame.view_model.remote_file_input import RemoteFileInputViewModel
15
14
 
15
+ from .input_field import InputField
16
+
16
17
 
17
18
  class RemoteFileInput:
18
19
  """Generates a file selection dialog for picking files off of the server.
@@ -189,3 +190,11 @@ class RemoteFileInput:
189
190
  )
190
191
  self.vm.showing_all_bind.connect(self.vm.get_showing_all_state_name())
191
192
  self.vm.valid_selection_bind.connect(self.vm.get_valid_selection_state_name())
193
+
194
+ def select_file(self, value: str) -> None:
195
+ """Programmatically set the v_model value."""
196
+ self.vm.select_file(value)
197
+
198
+ def open_dialog(self) -> None:
199
+ """Programmatically opens the dialog for selecting a file."""
200
+ self.vm.open_dialog()
@@ -12,12 +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
15
  .mpl-message, .ui-dialog-titlebar {
22
16
  display: none !important;
23
17
  }
@@ -48,6 +42,12 @@ html {
48
42
  border-radius: 4px;
49
43
  }
50
44
 
45
+ .v-tab.v-btn {
46
+ height: 30px !important;
47
+ min-width: fit-content !important;
48
+ padding: 10px !important;
49
+ }
50
+
51
51
  .v-card-title,
52
52
  .v-list-item-title,
53
53
  .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",
@@ -156,12 +152,27 @@
156
152
  "secondary": "#f48e5c"
157
153
  },
158
154
  "defaults": {
155
+ "VAutocomplete": {
156
+ "variant": "outlined"
157
+ },
159
158
  "VBadge": {
160
159
  "dot": true
161
160
  },
162
161
  "VBtn": {
163
162
  "size": "small"
164
163
  },
164
+ "VCombobox": {
165
+ "variant": "outlined"
166
+ },
167
+ "VFileInput": {
168
+ "variant": "outlined"
169
+ },
170
+ "VSelect": {
171
+ "variant": "outlined"
172
+ },
173
+ "VTextarea": {
174
+ "variant": "outlined"
175
+ },
165
176
  "VTextField": {
166
177
  "VBtn": {
167
178
  "size": "small",
@@ -183,4 +194,4 @@
183
194
  "lighten": 5
184
195
  }
185
196
  }
186
- }
197
+ }
@@ -31,13 +31,6 @@ class ThemedApp:
31
31
  """Automatically injects theming into your Trame application.
32
32
 
33
33
  You should always inherit from this class when you define your Trame application.
34
-
35
- Currently, it supports two themes:
36
-
37
- 1. ModernTheme - The recommended theme for most applications. Leverages ORNL brand colors and a typical Vuetify \
38
- appearance.
39
- 2. CompactTheme - Similar to ModernTheme but with a smaller global font size and reduced margins and paddings on \
40
- all components.
41
34
  """
42
35
 
43
36
  def __init__(
@@ -151,7 +144,10 @@ class ThemedApp:
151
144
  Parameters
152
145
  ----------
153
146
  theme : str, optional
154
- The new theme to use. If the theme is not found, the default theme will be used.
147
+ The new theme to use. If the theme is not found, the default theme will be used. The available options are:
148
+
149
+ 1. ModernTheme (default) - Leverages ORNL brand colors and a typical Vuetify appearance.
150
+ 2. CompactTheme - Similar to ModernTheme but with a smaller global font size and increased density.
155
151
  force : bool, optional
156
152
  If True, the theme will be set even if the theme selection menu is disabled.
157
153
 
@@ -237,7 +233,7 @@ class ThemedApp:
237
233
  # [slot override example]
238
234
  layout.pre_content = vuetify.VSheet(classes="bg-background ")
239
235
  # [slot override example complete]
240
- with vuetify.VContainer(classes="flex-1-1 overflow-hidden pt-0 pb-0", fluid=True):
236
+ with vuetify.VContainer(classes="flex-0-1 overflow-hidden pt-0 pb-0", fluid=True):
241
237
  layout.content = html.Div(classes="h-100 overflow-y-auto pb-1 ")
242
238
  layout.post_content = vuetify.VSheet(classes="bg-background ")
243
239
 
@@ -1,6 +1,5 @@
1
1
  """View model implementation for the DataSelector widget."""
2
2
 
3
- import os
4
3
  from typing import Any, Optional
5
4
 
6
5
  from nova.mvvm.interface import BindingInterface
@@ -30,5 +29,5 @@ class DataSelectorViewModel:
30
29
  self.experiments_bind.update_in_view(self.model.get_experiments())
31
30
 
32
31
  datafile_paths = self.model.get_datafiles()
33
- datafile_options = [{"title": os.path.basename(datafile), "value": datafile} for datafile in datafile_paths]
32
+ datafile_options = [{"file": datafile} for datafile in datafile_paths]
34
33
  self.datafiles_bind.update_in_view(datafile_options)
@@ -35,6 +35,8 @@ class RemoteFileInputViewModel:
35
35
  self.previous_value = self.value
36
36
  self.populate_file_list()
37
37
 
38
+ self.dialog_bind.update_in_view(True)
39
+
38
40
  def close_dialog(self, cancel: bool = False) -> None:
39
41
  if not cancel:
40
42
  self.on_update_bind.update_in_view(self.value)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: nova-trame
3
- Version: 0.18.0.dev1
3
+ Version: 0.19.0.dev0
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
@@ -25,6 +25,7 @@ Requires-Dist: trame-matplotlib
25
25
  Requires-Dist: trame-plotly
26
26
  Requires-Dist: trame-vega
27
27
  Requires-Dist: trame-vuetify
28
+ Project-URL: Changelog, https://code.ornl.gov/ndip/public-packages/nova-trame/blob/main/CHANGELOG.md
28
29
  Description-Content-Type: text/markdown
29
30
 
30
31
  nova-trame
@@ -1,11 +1,12 @@
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=Uz5fS-oQU1cKfrzWFU0nKk0-gfYDcMuUFuwBWmhIRGU,3596
3
+ nova/trame/model/data_selector.py,sha256=xM4j_BrKXClRbeDjfcCQEAnWWYuUod7GxiF1WXDpfls,4620
4
4
  nova/trame/model/remote_file_input.py,sha256=9KAf31ZHzpsh_aXUrNcF81Q5jvUZDWCzW1QATKls-Jk,3675
5
- nova/trame/view/components/__init__.py,sha256=N4ERzfeALckuXgZnGZSR0kLLUsGlTiPcfqljiM2vKTg,184
6
- nova/trame/view/components/data_selector.py,sha256=MIC5VzQ-Gv6VQvmir7Nzip4wOtHKCB6LHBrswmeTw8I,4259
5
+ nova/trame/view/components/__init__.py,sha256=u8yzshFp_TmuC1g9TRxKjy_BdGWMIzPQouI52hzcr2U,234
6
+ nova/trame/view/components/data_selector.py,sha256=-u73LayMwepOVLsWx6P_z5tBTPGX0ekzlI9fFVv2sNk,5107
7
+ nova/trame/view/components/file_upload.py,sha256=MafxZQE9fIuDFoizW2I4jAb7n82DPNaOvVhrrPEMbq8,3029
7
8
  nova/trame/view/components/input_field.py,sha256=ncVVSzdJwH_-KP24I2rCqcb6v3J2hPhNTXr8Lb1EZ_U,15931
8
- nova/trame/view/components/remote_file_input.py,sha256=k2yrwkell_g0sGnWR9XLL1LxkmFLr8-AGhduo8E-N4A,8669
9
+ nova/trame/view/components/remote_file_input.py,sha256=0qi4PnmqUBIdUv36dUqYsTWRQ4fHUJ0nlg9oXzA3Qfs,8929
9
10
  nova/trame/view/components/visualization/__init__.py,sha256=reqkkbhD5uSksHHlhVMy1qNUCwSekS5HlXk6wCREYxU,152
10
11
  nova/trame/view/components/visualization/interactive_2d_plot.py,sha256=foZCMoqbuahT5dtqIQvm8C4ZJcY9P211eJEcpQJltmM,3421
11
12
  nova/trame/view/components/visualization/matplotlib_figure.py,sha256=yop7Kd_MylUiCwEial2jOYESbvchrYhrpSmRowUhePY,12003
@@ -14,18 +15,18 @@ nova/trame/view/layouts/grid.py,sha256=k-QHuH31XeAVDuMKUMoAMVnAM-Yavq7kdLYOC1ZrG
14
15
  nova/trame/view/layouts/hbox.py,sha256=r5irhFX6YWTWN4V4NwNQx6mheyM8p6PVcJbrbhvOAwo,2625
15
16
  nova/trame/view/layouts/vbox.py,sha256=Q4EvrtGJORyNF6AnCLGXToy8XU6yofiO5_kt7hK-AYs,2626
16
17
  nova/trame/view/theme/__init__.py,sha256=70_marDlTigIcPEOGiJb2JTs-8b2sGM5SlY7XBPtBDM,54
17
- nova/trame/view/theme/assets/core_style.scss,sha256=OtiO9E4FWFPkSL25LG6lwHyjKwywOsODRe9aOvL3Fj4,1513
18
+ nova/trame/view/theme/assets/core_style.scss,sha256=zZj7klB_iieNNTdh3WADpRbCA6WII0-nG86MKFEBYWY,1533
18
19
  nova/trame/view/theme/assets/favicon.png,sha256=Xbp1nUmhcBDeObjsebEbEAraPDZ_M163M_ZLtm5AbQc,1927
19
20
  nova/trame/view/theme/assets/js/delay_manager.js,sha256=vmb34DZ5YCQIlRW9Tf2M_uvJW6HFCmtlKZ5e_TPR8yg,536
20
21
  nova/trame/view/theme/assets/js/lodash.debounce.min.js,sha256=GLzlQH04WDUNYN7i39ttHHejSdu-CpAvfWgDgKDn-OY,4448
21
22
  nova/trame/view/theme/assets/js/lodash.throttle.min.js,sha256=9csqjX-M-LVGJnF3z4ha1R_36O5AfkFE8rPHkxmt3tE,4677
22
- nova/trame/view/theme/assets/vuetify_config.json,sha256=T2AtYBCXsYj5KDMUP0drO2wF9AVVGX4gHbt7LLovPzw,4927
23
- nova/trame/view/theme/theme.py,sha256=18tHChrB1_qosjIiiLxMwWYRDTdXfgxEP4-4yJ8E3Cw,11893
23
+ nova/trame/view/theme/assets/vuetify_config.json,sha256=axz6cEWE_v1fO9XbM7cCKJghJp2DbU0lH6TuKYEG9j0,5311
24
+ nova/trame/view/theme/theme.py,sha256=OFUtq1IWriFcDu-346J67ZrSES8IOI9PTY_4Vwg7bZQ,11820
24
25
  nova/trame/view/utilities/local_storage.py,sha256=vD8f2VZIpxhIKjZwEaD7siiPCTZO4cw9AfhwdawwYLY,3218
25
- nova/trame/view_model/data_selector.py,sha256=fUXqDKCueJcSk45DW_oqn_gVhEH56xS6FPk-7OZZHXg,1489
26
- nova/trame/view_model/remote_file_input.py,sha256=WHWCQkZBGeKLe1aTPbtVNI8tn-PDt64mi1-561uuBpQ,3320
27
- nova_trame-0.18.0.dev1.dist-info/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
28
- nova_trame-0.18.0.dev1.dist-info/METADATA,sha256=3u6lqn6MQGz7yHDCJ56_Cc_X-xgjog-LZ3RZq4dG7gE,1350
29
- nova_trame-0.18.0.dev1.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
30
- nova_trame-0.18.0.dev1.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
31
- nova_trame-0.18.0.dev1.dist-info/RECORD,,
26
+ nova/trame/view_model/data_selector.py,sha256=baijpcbKCUk0BITPpbhHR6nAG-SF5ho2EyEfARTvDAo,1441
27
+ nova/trame/view_model/remote_file_input.py,sha256=ojEOJ8ZPkajpbAaZi9VLj7g-uBjhb8BMrTdMmwf_J6A,3367
28
+ nova_trame-0.19.0.dev0.dist-info/LICENSE,sha256=Iu5QiDbwNbREg75iYaxIJ_V-zppuv4QFuBhAW-qiAlM,1061
29
+ nova_trame-0.19.0.dev0.dist-info/METADATA,sha256=Sf87sw5O7ATqba0bt-KUVtkGrkmY6oKmueowQAKFPw0,1451
30
+ nova_trame-0.19.0.dev0.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
31
+ nova_trame-0.19.0.dev0.dist-info/entry_points.txt,sha256=J2AmeSwiTYZ4ZqHHp9HO6v4MaYQTTBPbNh6WtoqOT58,42
32
+ nova_trame-0.19.0.dev0.dist-info/RECORD,,