ivoryos 1.0.9__py3-none-any.whl → 1.4.4__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.
- docs/source/conf.py +84 -0
- ivoryos/__init__.py +17 -207
- ivoryos/app.py +154 -0
- ivoryos/config.py +1 -0
- ivoryos/optimizer/ax_optimizer.py +191 -0
- ivoryos/optimizer/base_optimizer.py +84 -0
- ivoryos/optimizer/baybe_optimizer.py +193 -0
- ivoryos/optimizer/nimo_optimizer.py +173 -0
- ivoryos/optimizer/registry.py +11 -0
- ivoryos/routes/auth/auth.py +43 -14
- ivoryos/routes/auth/templates/change_password.html +32 -0
- ivoryos/routes/control/control.py +101 -366
- ivoryos/routes/control/control_file.py +33 -0
- ivoryos/routes/control/control_new_device.py +152 -0
- ivoryos/routes/control/templates/controllers.html +193 -0
- ivoryos/routes/control/templates/controllers_new.html +112 -0
- ivoryos/routes/control/utils.py +40 -0
- ivoryos/routes/data/data.py +197 -0
- ivoryos/routes/data/templates/components/step_card.html +78 -0
- ivoryos/routes/{database/templates/database → data/templates}/workflow_database.html +14 -8
- ivoryos/routes/data/templates/workflow_view.html +360 -0
- ivoryos/routes/design/__init__.py +4 -0
- ivoryos/routes/design/design.py +348 -657
- ivoryos/routes/design/design_file.py +68 -0
- ivoryos/routes/design/design_step.py +171 -0
- ivoryos/routes/design/templates/components/action_form.html +53 -0
- ivoryos/routes/design/templates/components/actions_panel.html +25 -0
- ivoryos/routes/design/templates/components/autofill_toggle.html +10 -0
- ivoryos/routes/design/templates/components/canvas.html +5 -0
- ivoryos/routes/design/templates/components/canvas_footer.html +9 -0
- ivoryos/routes/design/templates/components/canvas_header.html +75 -0
- ivoryos/routes/design/templates/components/canvas_main.html +39 -0
- ivoryos/routes/design/templates/components/deck_selector.html +10 -0
- ivoryos/routes/design/templates/components/edit_action_form.html +53 -0
- ivoryos/routes/design/templates/components/info_modal.html +318 -0
- ivoryos/routes/design/templates/components/instruments_panel.html +88 -0
- ivoryos/routes/design/templates/components/modals/drop_modal.html +17 -0
- ivoryos/routes/design/templates/components/modals/json_modal.html +22 -0
- ivoryos/routes/design/templates/components/modals/new_script_modal.html +17 -0
- ivoryos/routes/design/templates/components/modals/rename_modal.html +23 -0
- ivoryos/routes/design/templates/components/modals/saveas_modal.html +27 -0
- ivoryos/routes/design/templates/components/modals.html +6 -0
- ivoryos/routes/design/templates/components/python_code_overlay.html +56 -0
- ivoryos/routes/design/templates/components/sidebar.html +15 -0
- ivoryos/routes/design/templates/components/text_to_code_panel.html +20 -0
- ivoryos/routes/design/templates/experiment_builder.html +44 -0
- ivoryos/routes/execute/__init__.py +0 -0
- ivoryos/routes/execute/execute.py +377 -0
- ivoryos/routes/execute/execute_file.py +78 -0
- ivoryos/routes/execute/templates/components/error_modal.html +20 -0
- ivoryos/routes/execute/templates/components/logging_panel.html +56 -0
- ivoryos/routes/execute/templates/components/progress_panel.html +27 -0
- ivoryos/routes/execute/templates/components/run_panel.html +9 -0
- ivoryos/routes/execute/templates/components/run_tabs.html +60 -0
- ivoryos/routes/execute/templates/components/tab_bayesian.html +520 -0
- ivoryos/routes/execute/templates/components/tab_configuration.html +383 -0
- ivoryos/routes/execute/templates/components/tab_repeat.html +18 -0
- ivoryos/routes/execute/templates/experiment_run.html +30 -0
- ivoryos/routes/library/__init__.py +0 -0
- ivoryos/routes/library/library.py +157 -0
- ivoryos/routes/{database/templates/database/scripts_database.html → library/templates/library.html} +32 -23
- ivoryos/routes/main/main.py +31 -3
- ivoryos/routes/main/templates/{main/home.html → home.html} +4 -4
- ivoryos/server.py +180 -0
- ivoryos/socket_handlers.py +52 -0
- ivoryos/static/ivoryos_logo.png +0 -0
- ivoryos/static/js/action_handlers.js +384 -0
- ivoryos/static/js/db_delete.js +23 -0
- ivoryos/static/js/script_metadata.js +39 -0
- ivoryos/static/js/socket_handler.js +40 -5
- ivoryos/static/js/sortable_design.js +107 -56
- ivoryos/static/js/ui_state.js +114 -0
- ivoryos/templates/base.html +67 -8
- ivoryos/utils/bo_campaign.py +180 -3
- ivoryos/utils/client_proxy.py +267 -36
- ivoryos/utils/db_models.py +300 -65
- ivoryos/utils/decorators.py +34 -0
- ivoryos/utils/form.py +63 -29
- ivoryos/utils/global_config.py +34 -1
- ivoryos/utils/nest_script.py +314 -0
- ivoryos/utils/py_to_json.py +295 -0
- ivoryos/utils/script_runner.py +599 -165
- ivoryos/utils/serilize.py +201 -0
- ivoryos/utils/task_runner.py +71 -21
- ivoryos/utils/utils.py +50 -6
- ivoryos/version.py +1 -1
- ivoryos-1.4.4.dist-info/METADATA +263 -0
- ivoryos-1.4.4.dist-info/RECORD +119 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.4.4.dist-info}/WHEEL +1 -1
- {ivoryos-1.0.9.dist-info → ivoryos-1.4.4.dist-info}/top_level.txt +1 -0
- tests/unit/test_type_conversion.py +42 -0
- tests/unit/test_util.py +3 -0
- ivoryos/routes/control/templates/control/controllers.html +0 -78
- ivoryos/routes/control/templates/control/controllers_home.html +0 -55
- ivoryos/routes/control/templates/control/controllers_new.html +0 -89
- ivoryos/routes/database/database.py +0 -306
- ivoryos/routes/database/templates/database/step_card.html +0 -7
- ivoryos/routes/database/templates/database/workflow_view.html +0 -130
- ivoryos/routes/design/templates/design/experiment_builder.html +0 -521
- ivoryos/routes/design/templates/design/experiment_run.html +0 -558
- ivoryos-1.0.9.dist-info/METADATA +0 -218
- ivoryos-1.0.9.dist-info/RECORD +0 -61
- /ivoryos/routes/auth/templates/{auth/login.html → login.html} +0 -0
- /ivoryos/routes/auth/templates/{auth/signup.html → signup.html} +0 -0
- /ivoryos/routes/{database → data}/__init__.py +0 -0
- /ivoryos/routes/main/templates/{main/help.html → help.html} +0 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.4.4.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ivoryos
|
|
3
|
+
Version: 1.4.4
|
|
4
|
+
Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
|
|
5
|
+
Author-email: Ivory Zhang <ivoryzhang@chem.ubc.ca>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://gitlab.com/heingroup/ivoryos
|
|
8
|
+
Requires-Python: >=3.7
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Requires-Dist: bcrypt
|
|
12
|
+
Requires-Dist: Flask[async]
|
|
13
|
+
Requires-Dist: Flask-Login
|
|
14
|
+
Requires-Dist: Flask-Session
|
|
15
|
+
Requires-Dist: Flask-SocketIO
|
|
16
|
+
Requires-Dist: Flask-SQLAlchemy
|
|
17
|
+
Requires-Dist: Flask-WTF
|
|
18
|
+
Requires-Dist: SQLAlchemy-Utils
|
|
19
|
+
Requires-Dist: python-dotenv
|
|
20
|
+
Requires-Dist: pandas
|
|
21
|
+
Requires-Dist: astor; python_version < "3.9"
|
|
22
|
+
Provides-Extra: optimizer-ax
|
|
23
|
+
Requires-Dist: ax-platform; extra == "optimizer-ax"
|
|
24
|
+
Provides-Extra: optimizer-baybe
|
|
25
|
+
Requires-Dist: baybe; extra == "optimizer-baybe"
|
|
26
|
+
Provides-Extra: optimizer-nimo
|
|
27
|
+
Requires-Dist: nimo; extra == "optimizer-nimo"
|
|
28
|
+
Provides-Extra: optimizers
|
|
29
|
+
Requires-Dist: ax-platform>=1.1.2; extra == "optimizers"
|
|
30
|
+
Requires-Dist: baybe>=0.14.0; extra == "optimizers"
|
|
31
|
+
Requires-Dist: nimo; extra == "optimizers"
|
|
32
|
+
Provides-Extra: doc
|
|
33
|
+
Requires-Dist: sphinx; extra == "doc"
|
|
34
|
+
Requires-Dist: sphinx-rtd-theme; extra == "doc"
|
|
35
|
+
Requires-Dist: sphinxcontrib-httpdomain; extra == "doc"
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest; extra == "dev"
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
|
|
40
|
+
[](https://ivoryos.readthedocs.io/en/latest/?badge=latest)
|
|
41
|
+
[](https://pypi.org/project/ivoryos/)
|
|
42
|
+

|
|
43
|
+
[](https://youtu.be/dFfJv9I2-1g)
|
|
44
|
+
[](https://youtu.be/flr5ydiE96s)
|
|
45
|
+
[](https://www.nature.com/articles/s41467-025-60514-w)
|
|
46
|
+
|
|
47
|
+
[//]: # ([](https://discord.gg/AX5P9EdGVX))
|
|
48
|
+
|
|
49
|
+

|
|
50
|
+
|
|
51
|
+
# [IvoryOS](https://ivoryos.ai): interoperable orchestrator for self-driving laboratories (SDLs)
|
|
52
|
+
|
|
53
|
+
A **plug-and-play** web interface for flexible, modular SDLs —
|
|
54
|
+
you focus on developing protocols, IvoryOS handles the rest.
|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Table of Contents
|
|
61
|
+
- [What IvoryOS does](#what-ivoryos-does)
|
|
62
|
+
- [System requirements](#system-requirements)
|
|
63
|
+
- [Installation](#installation)
|
|
64
|
+
- [Features](#features)
|
|
65
|
+
- [Demo](#demo)
|
|
66
|
+
- [Roadmap](#roadmap)
|
|
67
|
+
- [Contributing](#contributing)
|
|
68
|
+
- [Acknowledgements](#acknowledgements)
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
## What IvoryOS Does
|
|
72
|
+
- Turns Python modules into UIs by dynamically inspecting your hardware APIs, functions, and workflows.
|
|
73
|
+
- Standardizes optimization inputs/outputs, making any optimizer plug-and-play.
|
|
74
|
+
- Provides a visual workflow builder for designing and running experiments.
|
|
75
|
+
- Adds natural-language control for creating and executing workflows, see [IvoryOS MCP](https://gitlab.com/heingroup/ivoryos-suite/ivoryos-mcp) for more details.
|
|
76
|
+
|
|
77
|
+
----
|
|
78
|
+
## System Requirements
|
|
79
|
+
|
|
80
|
+
**Platforms:** Compatible with Linux, macOS, and Windows (developed/tested on Windows).
|
|
81
|
+
**Python:**
|
|
82
|
+
- Recommended: Python ≥3.10
|
|
83
|
+
- Minimum: Python ≥3.7 (without Ax optimizer support)
|
|
84
|
+
|
|
85
|
+
**Core Dependencies:**
|
|
86
|
+
<details>
|
|
87
|
+
<summary>Click to expand</summary>
|
|
88
|
+
|
|
89
|
+
- bcrypt~=4.0
|
|
90
|
+
- Flask-Login~=0.6
|
|
91
|
+
- Flask-Session~=0.8
|
|
92
|
+
- Flask-SocketIO~=5.3
|
|
93
|
+
- Flask-SQLAlchemy~=3.1
|
|
94
|
+
- SQLAlchemy-Utils~=0.41
|
|
95
|
+
- Flask-WTF~=1.2
|
|
96
|
+
- python-dotenv==1.0.1
|
|
97
|
+
- pandas
|
|
98
|
+
|
|
99
|
+
**Optional:**
|
|
100
|
+
- ax-platform==1.1.2
|
|
101
|
+
- baybe==0.14.0
|
|
102
|
+
- nimo
|
|
103
|
+
- slack-sdk
|
|
104
|
+
</details>
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## Installation
|
|
110
|
+
From PyPI:
|
|
111
|
+
```bash
|
|
112
|
+
pip install ivoryos
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
[//]: # (From source:)
|
|
116
|
+
|
|
117
|
+
[//]: # (```bash)
|
|
118
|
+
|
|
119
|
+
[//]: # (git clone https://gitlab.com/heingroup/ivoryos.git)
|
|
120
|
+
|
|
121
|
+
[//]: # (cd ivoryos)
|
|
122
|
+
|
|
123
|
+
[//]: # (pip install -e .)
|
|
124
|
+
|
|
125
|
+
[//]: # (```)
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
## Quick start
|
|
129
|
+
In your script, where you initialize or import your robot:
|
|
130
|
+
```python
|
|
131
|
+
my_robot = Robot()
|
|
132
|
+
|
|
133
|
+
import ivoryos
|
|
134
|
+
|
|
135
|
+
ivoryos.run(__name__)
|
|
136
|
+
```
|
|
137
|
+
Then run the script and visit `http://localhost:8000` in your browser.
|
|
138
|
+
Use `admin` for both username and password, and start building workflows!
|
|
139
|
+
|
|
140
|
+
----
|
|
141
|
+
## Features
|
|
142
|
+
### Direct control:
|
|
143
|
+
direct function calling _Devices_ tab
|
|
144
|
+
### Workflows
|
|
145
|
+
- **Design Editor**: drag/add function to canvas in _Design_ tab. click `Compile and Run` button to go to the execution configuration page
|
|
146
|
+
- **Execution Config**: configure iteration methods and parameters in _Compile/Run_ tab.
|
|
147
|
+
- **Design Library**: manage workflow scripts in _Library_ tab.
|
|
148
|
+
- **Workflow Data**: Execution records are in _Data_ tab.
|
|
149
|
+
### Offline mode
|
|
150
|
+
after one successful connection, a blueprint will be automatically saved and made accessible without hardware connection. In a new Python script in the same directory, use `ivoryos.run()` to start offline mode.
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
### Logging
|
|
155
|
+
Add single or multiple loggers:
|
|
156
|
+
```python
|
|
157
|
+
ivoryos.run(__name__, logger="logger name")
|
|
158
|
+
ivoryos.run(__name__, logger=["logger 1", "logger 2"])
|
|
159
|
+
```
|
|
160
|
+
### Human-in-the-loop
|
|
161
|
+
Use `pause` in flow control to pause the workflow and send a notification with custom message handler(s).
|
|
162
|
+
When run into `pause`, it will pause, send a message, and wait for human's response. Example of a Slack bot:
|
|
163
|
+
```python
|
|
164
|
+
|
|
165
|
+
def slack_bot(msg: str = "Hi"):
|
|
166
|
+
"""
|
|
167
|
+
a function that can be used as a notification handler function("msg")
|
|
168
|
+
:param msg: message to send
|
|
169
|
+
"""
|
|
170
|
+
from slack_sdk import WebClient
|
|
171
|
+
|
|
172
|
+
slack_token = "your slack token"
|
|
173
|
+
client = WebClient(token=slack_token)
|
|
174
|
+
|
|
175
|
+
my_user_id = "your user id" # replace with your actual Slack user ID
|
|
176
|
+
|
|
177
|
+
client.chat_postMessage(channel=my_user_id, text=msg)
|
|
178
|
+
|
|
179
|
+
import ivoryos
|
|
180
|
+
ivoryos.run(__name__, notification_handler=slack_bot)
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Directory Structure
|
|
184
|
+
|
|
185
|
+
Created automatically in the same working directory on the first run:
|
|
186
|
+
<details>
|
|
187
|
+
<summary>click to see the data folder structure</summary>
|
|
188
|
+
|
|
189
|
+
- **`ivoryos_data/`**:
|
|
190
|
+
- **`config_csv/`**: Batch configuration `csv`
|
|
191
|
+
- **`pseudo_deck/`**: Offline deck `.pkl`
|
|
192
|
+
- **`results/`**: Execution results
|
|
193
|
+
- **`scripts/`**: Compiled workflows Python scripts
|
|
194
|
+
- **`default.log`**: Application logs
|
|
195
|
+
- **`ivoryos.db`**: Local database
|
|
196
|
+
</details>
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Demo
|
|
201
|
+
Online demo at [demo.ivoryos.ai](https://demo.ivoryos.ai).
|
|
202
|
+
Local version in [abstract_sdl.py](https://gitlab.com/heingroup/ivoryos/-/blob/main/community/examples/abstract_sdl_example/abstract_sdl.py)
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Roadmap
|
|
207
|
+
|
|
208
|
+
- [ ] dropdown input
|
|
209
|
+
- [ ] snapshot version control
|
|
210
|
+
- [ ] check batch-config file compatibility
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Contributing
|
|
215
|
+
|
|
216
|
+
We welcome all contributions — from core improvements to new drivers, plugins, and real-world use cases.
|
|
217
|
+
See `CONTRIBUTING.md` for details and let us know you're interested: https://forms.gle/fPSvw5LEGrweUQUH8
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## Citing
|
|
222
|
+
|
|
223
|
+
<details>
|
|
224
|
+
<summary>Click to see citations</summary>
|
|
225
|
+
|
|
226
|
+
If you find this project useful, please consider citing the following manuscript:
|
|
227
|
+
|
|
228
|
+
> Zhang, W., Hao, L., Lai, V. et al. [IvoryOS: an interoperable web interface for orchestrating Python-based self-driving laboratories.](https://www.nature.com/articles/s41467-025-60514-w) Nat Commun 16, 5182 (2025).
|
|
229
|
+
|
|
230
|
+
```bibtex
|
|
231
|
+
@article{zhang_et_al_2025,
|
|
232
|
+
author = {Wenyu Zhang and Lucy Hao and Veronica Lai and Ryan Corkery and Jacob Jessiman and Jiayu Zhang and Junliang Liu and Yusuke Sato and Maria Politi and Matthew E. Reish and Rebekah Greenwood and Noah Depner and Jiyoon Min and Rama El-khawaldeh and Paloma Prieto and Ekaterina Trushina and Jason E. Hein},
|
|
233
|
+
title = {{IvoryOS}: an interoperable web interface for orchestrating {Python-based} self-driving laboratories},
|
|
234
|
+
journal = {Nature Communications},
|
|
235
|
+
year = {2025},
|
|
236
|
+
volume = {16},
|
|
237
|
+
number = {1},
|
|
238
|
+
pages = {5182},
|
|
239
|
+
doi = {10.1038/s41467-025-60514-w},
|
|
240
|
+
url = {https://doi.org/10.1038/s41467-025-60514-w}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
For an additional perspective related to the development of the tool, please see:
|
|
245
|
+
|
|
246
|
+
> Zhang, W., Hein, J. [Behind IvoryOS: Empowering Scientists to Harness Self-Driving Labs for Accelerated Discovery](https://communities.springernature.com/posts/behind-ivoryos-empowering-scientists-to-harness-self-driving-labs-for-accelerated-discovery). Springer Nature Research Communities (2025).
|
|
247
|
+
|
|
248
|
+
```bibtex
|
|
249
|
+
@misc{zhang_hein_2025,
|
|
250
|
+
author = {Wenyu Zhang and Jason Hein},
|
|
251
|
+
title = {Behind {IvoryOS}: Empowering Scientists to Harness Self-Driving Labs for Accelerated Discovery},
|
|
252
|
+
howpublished = {Springer Nature Research Communities},
|
|
253
|
+
year = {2025},
|
|
254
|
+
month = {Jun},
|
|
255
|
+
day = {18},
|
|
256
|
+
url = {https://communities.springernature.com/posts/behind-ivoryos-empowering-scientists-to-harness-self-driving-labs-for-accelerated-discovery}
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
</details>
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
## Acknowledgements
|
|
263
|
+
Authors acknowledge Telescope Innovations Corp., UBC Hein Lab, and Acceleration Consortium members for their valuable suggestions and contributions.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
docs/source/conf.py,sha256=hETfkDMTdj-NYgSI_671gVOVd7iwqU3tEeXnQe2xEWs,2004
|
|
2
|
+
ivoryos/__init__.py,sha256=gEvBO2y5TRq06Itjjej3iAcq73UsihqKPWcb2HykPwM,463
|
|
3
|
+
ivoryos/app.py,sha256=TG-RctBKj8VVOeXciYZ2s_ehP01PACwvLRfl2f3vF6w,5561
|
|
4
|
+
ivoryos/config.py,sha256=y3RxNjiIola9tK7jg-mHM8EzLMwiLwOzoisXkDvj0gA,2174
|
|
5
|
+
ivoryos/server.py,sha256=9zw3c4IGj3DCtjRzEdEG3N4uxAtRZA1fowQGW1d_y94,7208
|
|
6
|
+
ivoryos/socket_handlers.py,sha256=KSh8TxbLFTcmaa-lEb5rKJvOYjKgnGTtaKZST8Wh3b8,1326
|
|
7
|
+
ivoryos/version.py,sha256=6stz_YFBRP_lguydVylsTgSmj3VTb6WFq8Sp45WYQyY,22
|
|
8
|
+
ivoryos/optimizer/ax_optimizer.py,sha256=43w4ollMfWn1DPB4jJ15pc13XxIktWjlxHn9NX339go,8566
|
|
9
|
+
ivoryos/optimizer/base_optimizer.py,sha256=m_wXan_xPueUWNQi3-561Pe_060tsKuUcCTOOu0qu8s,2652
|
|
10
|
+
ivoryos/optimizer/baybe_optimizer.py,sha256=grXmePNuTQsCgRDhJGsAWQuSvvt0hqjhvzpyrZKYjD0,8502
|
|
11
|
+
ivoryos/optimizer/nimo_optimizer.py,sha256=ZevLJUhJKpwatyiOSmPEz3JAUZTdZNKEc_J7z1fAvVQ,7303
|
|
12
|
+
ivoryos/optimizer/registry.py,sha256=dLMo5cszcwa06hfBxdINQIGpkHtRe5-J3J7t76Jq6X0,306
|
|
13
|
+
ivoryos/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
ivoryos/routes/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
+
ivoryos/routes/auth/auth.py,sha256=AkYnyI4u5ySshpwPK8Z0KVEbR9X1BGdrqDu_IDea-AM,4348
|
|
16
|
+
ivoryos/routes/auth/templates/change_password.html,sha256=GfnytIPyhiLgnc2FzX-aXad1IV2I0nE3A-BQ4KVdaA0,1517
|
|
17
|
+
ivoryos/routes/auth/templates/login.html,sha256=WSRrKbdM_oobqSXFRTo-j9UlOgp6sYzS9tm7TqqPULI,1207
|
|
18
|
+
ivoryos/routes/auth/templates/signup.html,sha256=b5LTXtpfTSkSS7X8u1ldwQbbgEFTk6UNMAediA5BwBY,1465
|
|
19
|
+
ivoryos/routes/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
20
|
+
ivoryos/routes/control/control.py,sha256=0g23PoPPoTeMD7Szm3UAW10sEMLpSD-iTfASAZE4iIE,6442
|
|
21
|
+
ivoryos/routes/control/control_file.py,sha256=3fQ9R8EcdqKs_hABn2EqRAB1xC2DHAT_q_pwsMIDDQI,864
|
|
22
|
+
ivoryos/routes/control/control_new_device.py,sha256=oHbNUjTyv9yh-4FNTxkJqunaZbyH0RiiLoqIjLYUTEQ,5725
|
|
23
|
+
ivoryos/routes/control/utils.py,sha256=XlhhqAtOj7n3XfHPDxJ8TvCV2K2I2IixB0CBkl1QeQc,1242
|
|
24
|
+
ivoryos/routes/control/templates/controllers.html,sha256=5hF3zcx5Rpy0Zaoq-5YGrR_TvPD9MGIa30fI4smEii0,9702
|
|
25
|
+
ivoryos/routes/control/templates/controllers_new.html,sha256=eVeLABT39DWOIYrwWClw7sAD3lCoAGCznygPgFbQoRc,5945
|
|
26
|
+
ivoryos/routes/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
27
|
+
ivoryos/routes/data/data.py,sha256=MR7Vu7HB9dWjVr3cPwJbfIvTWs1Rqh2uXOPWIEFivzs,6399
|
|
28
|
+
ivoryos/routes/data/templates/workflow_database.html,sha256=ofvHcovpwmJXo1SFiSrL8I9kLU_3U1UxsJUUrQ2CJUU,4878
|
|
29
|
+
ivoryos/routes/data/templates/workflow_view.html,sha256=NljmhBVBUYfoOkuUWpVYUYsQkBFPbKlmzYFmFY7KHvY,13011
|
|
30
|
+
ivoryos/routes/data/templates/components/step_card.html,sha256=fxTg-1_Vw8b8QzAUXsPMfFgTmcHo8esAdLTUvK1cKVI,3726
|
|
31
|
+
ivoryos/routes/design/__init__.py,sha256=zS3HXKaw0ALL5n6t_W1rUz5Uj5_tTQ-Y1VMXyzewvR0,113
|
|
32
|
+
ivoryos/routes/design/design.py,sha256=n7768F60Nx04ST7yZSoKiNsoRFCwKjFsZvdzveoFLq0,20042
|
|
33
|
+
ivoryos/routes/design/design_file.py,sha256=MVIc5uGSaGxZhs86hfPjX2n0iy1OcXeLq7b9Ucdg4VQ,2115
|
|
34
|
+
ivoryos/routes/design/design_step.py,sha256=W2mFKMOkbSDBk4Gx9wRYcwjeru2mj-ub1l_K4hPRuZY,6031
|
|
35
|
+
ivoryos/routes/design/templates/experiment_builder.html,sha256=B5NHnOfTbC8xIfmhIQZlQn1_eTd1Ld6c_q5xoMed_Hs,1747
|
|
36
|
+
ivoryos/routes/design/templates/components/action_form.html,sha256=kXJOrJLbFsMHHWVSuMQHpt1xFrUMnwgzTG8e6Qfn0Cg,3042
|
|
37
|
+
ivoryos/routes/design/templates/components/actions_panel.html,sha256=jHTR58saTUIZInBdC-vLc1ZTbStLiULeWbupjB4hQzo,977
|
|
38
|
+
ivoryos/routes/design/templates/components/autofill_toggle.html,sha256=CRVQUHoQT7sOSO5-Vax54ImHdT4G_mEgqR5OQkeUwK8,617
|
|
39
|
+
ivoryos/routes/design/templates/components/canvas.html,sha256=bKLCJaG1B36Yy9Vsnz4P5qiX4BPdfaGe9JeQQzu9rsI,268
|
|
40
|
+
ivoryos/routes/design/templates/components/canvas_footer.html,sha256=5VRRacMZbzx0hUej0NPP-PmXM_AtUqduHzDS7a60cQY,435
|
|
41
|
+
ivoryos/routes/design/templates/components/canvas_header.html,sha256=7iIzLDGHX7MnmBbf98nWtLDprbeIgoNV4dJUO1zE4Tc,3598
|
|
42
|
+
ivoryos/routes/design/templates/components/canvas_main.html,sha256=nLEtp3U2YtfJwob1kR8ua8-UVdu9hwc6z1L5UMNVz8c,1524
|
|
43
|
+
ivoryos/routes/design/templates/components/deck_selector.html,sha256=ryTRpljYezo0AzGLCJu_qOMokjjnft3GIxddmNGtBA0,657
|
|
44
|
+
ivoryos/routes/design/templates/components/edit_action_form.html,sha256=1xL0wueewp_Hdua9DzYJBry09Qcchh4XgGmt4qPCwnc,2782
|
|
45
|
+
ivoryos/routes/design/templates/components/info_modal.html,sha256=ifetOzL124a7NZFsJhjmm04fTaKyibHJ32I0ek0zPoA,19156
|
|
46
|
+
ivoryos/routes/design/templates/components/instruments_panel.html,sha256=tRKd-wOqKjaMJCLuGgRmHtxIgSjklhBkuX8arm5aTCU,4268
|
|
47
|
+
ivoryos/routes/design/templates/components/modals.html,sha256=6Dl8I8oD4ln7kK8C5e92pFVVH5KDte-vVTL0U_6NSTg,306
|
|
48
|
+
ivoryos/routes/design/templates/components/python_code_overlay.html,sha256=Iyk-wOzk1x2997kqGt3uJONh_rpi5sCUs7VCRDg8Q9U,2150
|
|
49
|
+
ivoryos/routes/design/templates/components/sidebar.html,sha256=A6dRo53zIB6QJVrRLJcBZHUNJ3qpYPnR3kWxM8gTkjw,501
|
|
50
|
+
ivoryos/routes/design/templates/components/text_to_code_panel.html,sha256=d-omdXk-PXAR5AyWPr4Rc4pqsebZOiTiMrnz3pPCnUY,1197
|
|
51
|
+
ivoryos/routes/design/templates/components/modals/drop_modal.html,sha256=LPxcycSiBjdQbajYOegjMQEi7ValcaczGoWmW8Sz3Ms,779
|
|
52
|
+
ivoryos/routes/design/templates/components/modals/json_modal.html,sha256=R-SeEdhtuDVbwOWYYH_hCdpul7y4ybCWoNwVIO5j49s,1122
|
|
53
|
+
ivoryos/routes/design/templates/components/modals/new_script_modal.html,sha256=pxZdWWDgI52VsTFzz6pIM9m_dTwR6jARcvCYQ6fV3Lc,937
|
|
54
|
+
ivoryos/routes/design/templates/components/modals/rename_modal.html,sha256=40rLNF9JprdXekB3mv_S3OdqVuQYOe-BZSCgOnIkxJQ,1202
|
|
55
|
+
ivoryos/routes/design/templates/components/modals/saveas_modal.html,sha256=N5PEqUuK3qxDFbtDKFnzHwhLarQLPHiX-XQAdQPL1AU,1555
|
|
56
|
+
ivoryos/routes/execute/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
57
|
+
ivoryos/routes/execute/execute.py,sha256=hf64lnhiFxjAXy7b5XsFbORKAlkFTQEtqbfrhdYplXk,14603
|
|
58
|
+
ivoryos/routes/execute/execute_file.py,sha256=TelWYV295p4ZPhkUDJSVxfYROfVaKodEmDPTS2plQHI,2816
|
|
59
|
+
ivoryos/routes/execute/templates/experiment_run.html,sha256=fvHRrG5ii1v5zPHL9N_ljDGHUo3t3amiproVPtnOFVE,944
|
|
60
|
+
ivoryos/routes/execute/templates/components/error_modal.html,sha256=5Dmp9V0Ys6781Y-pKn_mc4N9J46c8EwIkjkHX22xCsw,1025
|
|
61
|
+
ivoryos/routes/execute/templates/components/logging_panel.html,sha256=-elcawnE4CaumyivzxaHW3S5xSv5CgZtXt0OHljlits,2554
|
|
62
|
+
ivoryos/routes/execute/templates/components/progress_panel.html,sha256=-nX76aFLxSOiYgI1xMjznC9rDYF-Vb92TmfjXYpBtps,1323
|
|
63
|
+
ivoryos/routes/execute/templates/components/run_panel.html,sha256=CmK-LYJ4K6RonHn6l9eJkqRw0XQizThOugxiXZonSDs,373
|
|
64
|
+
ivoryos/routes/execute/templates/components/run_tabs.html,sha256=HZUBQxJIigp9DgMvcxZOoR_pqz4ZW9kpxhbCjW6_dRg,2724
|
|
65
|
+
ivoryos/routes/execute/templates/components/tab_bayesian.html,sha256=oxtXWb5rUo88yTyyB9dZNxfzi0YanKy8NS9SBuiZKbI,24864
|
|
66
|
+
ivoryos/routes/execute/templates/components/tab_configuration.html,sha256=uZQfi8QLIGbCvgQR2M-fuFAjW4id9ANlYgBUbTJfaZw,14878
|
|
67
|
+
ivoryos/routes/execute/templates/components/tab_repeat.html,sha256=s8Q9Vuztf_h0vy97CBjHwgMdbaLQwall6StVdbL6FY8,989
|
|
68
|
+
ivoryos/routes/library/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
69
|
+
ivoryos/routes/library/library.py,sha256=QKeP34COssXDipn3d9yEn7pVPYbPb-eFg_X0C8JTvVQ,5387
|
|
70
|
+
ivoryos/routes/library/templates/library.html,sha256=kMaQphkoGQdxIRcQmVcEIn8eghuv2AAClHpo7jGDVv8,4021
|
|
71
|
+
ivoryos/routes/main/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
72
|
+
ivoryos/routes/main/main.py,sha256=3hM85DB0edtjTh0YYVqwfWe0-gL2dX7F6HooTrCRvvs,1856
|
|
73
|
+
ivoryos/routes/main/templates/help.html,sha256=IOktMEsOPk0SCiMBXZ4mpffClERAyX8W82fel71M3M0,9370
|
|
74
|
+
ivoryos/routes/main/templates/home.html,sha256=BDvwkVthxniQ157H6E2hgYHT1Vv1GVBwu6dQejtzwoo,4633
|
|
75
|
+
ivoryos/static/favicon.ico,sha256=RhlrPtfITOkzC9BjP1UB1V5L9Oyp6NwNtWeMcGOnpyc,15406
|
|
76
|
+
ivoryos/static/ivoryos_logo.png,sha256=I-1POqhLdPveruxsFbKhKUKAXspHfyxvowpCRFxEzvc,11656
|
|
77
|
+
ivoryos/static/logo.webp,sha256=lXgfQR-4mHTH83k7VV9iB54-oC2ipe6uZvbwdOnLETc,14974
|
|
78
|
+
ivoryos/static/style.css,sha256=zQVx35A5g6JMJ-K84-6fSKtzXGjp_p5ZVG6KLHPM2IE,4021
|
|
79
|
+
ivoryos/static/gui_annotation/Slide1.png,sha256=Lm4gdOkUF5HIUFaB94tl6koQVkzpitKj43GXV_XYMMc,121727
|
|
80
|
+
ivoryos/static/gui_annotation/Slide2.PNG,sha256=z3wQ9oVgg4JTWVLQGKK_KhtepRHUYP1e05XUWGT2A0I,118761
|
|
81
|
+
ivoryos/static/js/action_handlers.js,sha256=VC_kHFk0KKE7Q20PNRSIyxUDgrl_-54Tr2w55JvlhCU,11512
|
|
82
|
+
ivoryos/static/js/db_delete.js,sha256=l67fqUaN_FVDaL7v91Hd7LyRbxnqXx9nyjF34-7aewY,561
|
|
83
|
+
ivoryos/static/js/overlay.js,sha256=dPxop19es0E0ZUSY3d_4exIk7CJuQEnlW5uTt5fZfzI,483
|
|
84
|
+
ivoryos/static/js/script_metadata.js,sha256=m8VYZ8OGT2oTx1kXMXq60bKQI9WCbJNkzcFDzLvRuGc,1188
|
|
85
|
+
ivoryos/static/js/socket_handler.js,sha256=5MGLj-nNA3053eBcko4MZAB5zq2mkgr1g__c_rr3cE8,6849
|
|
86
|
+
ivoryos/static/js/sortable_card.js,sha256=ifmlGe3yy0U_KzMphV4ClRhK2DLOvkELYMlq1vECuac,807
|
|
87
|
+
ivoryos/static/js/sortable_design.js,sha256=ZezDxKtFxqmqSLfFy-HJ61LvQSXL36imYud6TIREs3U,5503
|
|
88
|
+
ivoryos/static/js/ui_state.js,sha256=XYsOcfGlduqLlqHySvPrRrR50CiAsml51duqneigsRY,3368
|
|
89
|
+
ivoryos/templates/base.html,sha256=uJ5lcYUCImiOasyP3g1-dQ-9Fdkff0Re6uUEGud2ySo,12011
|
|
90
|
+
ivoryos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
91
|
+
ivoryos/utils/bo_campaign.py,sha256=Z4WXJwbf1Hhg1dtlvhWHncBiq9Cuaf0BiqR60bWy36U,10038
|
|
92
|
+
ivoryos/utils/client_proxy.py,sha256=74G3HAuq50iEHkSvlMZFmQaukm613FbRgOdzO_T3dMg,10191
|
|
93
|
+
ivoryos/utils/db_models.py,sha256=3cO5EcekYMDQQl3LujXR_8i0Lrgvs34BX34KUtafqwY,37994
|
|
94
|
+
ivoryos/utils/decorators.py,sha256=pcD8WijFjNfkNvr-wmJSWTHn_OqCOCpAO-7w_qg9_xM,1051
|
|
95
|
+
ivoryos/utils/form.py,sha256=MNIvmx4RhDukFACwyrXS-88tBeMKeNdxVba_KzOab_Y,23469
|
|
96
|
+
ivoryos/utils/global_config.py,sha256=leYoEXvAS0AH4xQpYsqu4HI9CJ9-wiLM-pIh_bEG4Ak,3087
|
|
97
|
+
ivoryos/utils/llm_agent.py,sha256=-lVCkjPlpLues9sNTmaT7bT4sdhWvV2DiojNwzB2Lcw,6422
|
|
98
|
+
ivoryos/utils/nest_script.py,sha256=kc4V0cBca5TviqQuquMFBF8Q5IjqKqj2R6g-_N6gMak,10645
|
|
99
|
+
ivoryos/utils/py_to_json.py,sha256=ZtejHgwdEAUCVVMYeVNR8G7ceLINue294q6WpiJ6jn0,9734
|
|
100
|
+
ivoryos/utils/script_runner.py,sha256=jjgloXAbcZprZmjeS-IXnw-KCIFQWKjPYqsv_PrN9Qs,32249
|
|
101
|
+
ivoryos/utils/serilize.py,sha256=lkBhkz8r2bLmz2_xOb0c4ptSSOqjIu6krj5YYK4Nvj8,6784
|
|
102
|
+
ivoryos/utils/task_runner.py,sha256=AnY0DwS5ytU5f7OfCFlNJ72yAonA3tla4UhC7MOM3mw,4818
|
|
103
|
+
ivoryos/utils/utils.py,sha256=n0tQKIsEIVqrWEjN8vJHmobDcZOPmvyrHxoBAdaQr4g,15414
|
|
104
|
+
ivoryos-1.4.4.dist-info/licenses/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
|
|
105
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
106
|
+
tests/conftest.py,sha256=u2sQ6U-Lghyl7et1Oz6J2E5VZ47VINKcjRM_2leAE2s,3627
|
|
107
|
+
tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
108
|
+
tests/integration/test_route_auth.py,sha256=l3ZDqr0oiCWS3yYSXGK5yMP6qI2t7Sv5I9zoYTkiyQU,2754
|
|
109
|
+
tests/integration/test_route_control.py,sha256=YYIll84bTUEKiAxFiFSz6LF3fTldPNfCtHs0IR3mSdM,3935
|
|
110
|
+
tests/integration/test_route_database.py,sha256=mS026W_hEuCTMpSkdRWvM-f4MYykK_6nRDJ4K5a7QA0,2342
|
|
111
|
+
tests/integration/test_route_design.py,sha256=PJAvGRiCY6B53Pu1v5vPAVHHsuaqRmRKk2eesSNshLU,1157
|
|
112
|
+
tests/integration/test_route_main.py,sha256=bmuf8Y_9CRWhiLLf4up11ltEd5YCdsLx6I-o26VGDEw,1228
|
|
113
|
+
tests/integration/test_sockets.py,sha256=4ZyFyExm7a-DYzVqpzEONpWeb1a0IT68wyFaQu0rY_Y,925
|
|
114
|
+
tests/unit/test_type_conversion.py,sha256=zJjlBZPF4U0TJDECdFgYHPf-7lIEoQ3uy015RIRgTTA,2346
|
|
115
|
+
tests/unit/test_util.py,sha256=XSrZ3V2gKYhr1qEniWU9RY2Rm7PnO06ZCM05GaElncI,76
|
|
116
|
+
ivoryos-1.4.4.dist-info/METADATA,sha256=NEmN9NwX6lx6QAbX4JQciWSJfRNrmoFfP5qdjA6QAPY,9135
|
|
117
|
+
ivoryos-1.4.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
118
|
+
ivoryos-1.4.4.dist-info/top_level.txt,sha256=ZxZvj1N-GvvGOSN8pBy9SU9Ohf3ehzJfmGDh-M-0YuI,19
|
|
119
|
+
ivoryos-1.4.4.dist-info/RECORD,,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
from unittest.mock import patch
|
|
2
|
+
|
|
3
|
+
from tests.conftest import TestEnum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_int_conversion(auth, test_deck):
|
|
7
|
+
"""Tests that a string from a form is converted to an integer."""
|
|
8
|
+
with patch('ivoryos.control.routes.global_config.deck_instance.deck_dummy.int_method') as mock_method:
|
|
9
|
+
auth.post('/ivoryos/control/deck.dummy/call/int_method', data={'arg': '123'})
|
|
10
|
+
# Check that the mock was called with an integer
|
|
11
|
+
mock_method.assert_called_with(arg=123)
|
|
12
|
+
|
|
13
|
+
def test_float_conversion(auth, test_deck):
|
|
14
|
+
"""Tests that a string from a form is converted to a float."""
|
|
15
|
+
with patch('ivoryos.control.routes.global_config.deck_instance.deck_dummy.float_method') as mock_method:
|
|
16
|
+
auth.post('/ivoryos/control/deck.dummy/call/float_method', data={'arg': '123.45'})
|
|
17
|
+
# Check that the mock was called with a float
|
|
18
|
+
mock_method.assert_called_with(arg=123.45)
|
|
19
|
+
|
|
20
|
+
def test_bool_conversion(auth, test_deck):
|
|
21
|
+
"""Tests that a string from a form is converted to a boolean."""
|
|
22
|
+
with patch('ivoryos.control.routes.global_config.deck_instance.deck_dummy.bool_method') as mock_method:
|
|
23
|
+
# Test with 'true'
|
|
24
|
+
auth.post('/ivoryos/control/deck.dummy/call/bool_method', data={'arg': 'true'})
|
|
25
|
+
mock_method.assert_called_with(arg=True)
|
|
26
|
+
# Test with 'false'
|
|
27
|
+
auth.post('/ivoryos/control/deck.dummy/call/bool_method', data={'arg': 'false'})
|
|
28
|
+
mock_method.assert_called_with(arg=False)
|
|
29
|
+
|
|
30
|
+
def test_list_conversion(auth, test_deck):
|
|
31
|
+
"""Tests that a comma-separated string from a form is converted to a list."""
|
|
32
|
+
with patch('ivoryos.control.routes.global_config.deck_instance.deck_dummy.list_method') as mock_method:
|
|
33
|
+
auth.post('/ivoryos/control/deck.dummy/call/list_method', data={'arg': 'a,b,c'})
|
|
34
|
+
# Check that the mock was called with a list of strings
|
|
35
|
+
mock_method.assert_called_with(arg=['a', 'b', 'c'])
|
|
36
|
+
|
|
37
|
+
def test_enum_conversion(auth, test_deck):
|
|
38
|
+
"""Tests that a string from a form is converted to an Enum member."""
|
|
39
|
+
with patch('ivoryos.control.routes.global_config.deck_instance.deck_dummy.enum_method') as mock_method:
|
|
40
|
+
auth.post('/ivoryos/control/deck.dummy/call/enum_method', data={'arg': 'OPTION_B'})
|
|
41
|
+
# Check that the mock was called with the correct Enum member
|
|
42
|
+
mock_method.assert_called_with(arg=TestEnum.OPTION_B)
|
tests/unit/test_util.py
ADDED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
{% extends 'base.html' %}
|
|
2
|
-
{% block title %}IvoryOS | Controller for {{instrument}}{% endblock %}
|
|
3
|
-
{% block body %}
|
|
4
|
-
<div id="overlay" class="overlay">
|
|
5
|
-
<div>
|
|
6
|
-
<h3 id="overlay-text"></h3>
|
|
7
|
-
<div class="spinner-border" role="status"></div>
|
|
8
|
-
</div>
|
|
9
|
-
</div>
|
|
10
|
-
<h1>{{instrument}} controller</h1>
|
|
11
|
-
{% set hidden = session.get('hidden_functions', {}) %}
|
|
12
|
-
<div class="grid-container" id="sortable-grid">
|
|
13
|
-
{% for function, form in forms.items() %}
|
|
14
|
-
|
|
15
|
-
{% set hidden_instrument = hidden.get(instrument, []) %}
|
|
16
|
-
{% if function not in hidden_instrument %}
|
|
17
|
-
<div class="card" id="{{function}}">
|
|
18
|
-
<div class="bg-white rounded shadow-sm flex-fill">
|
|
19
|
-
<i class="bi bi-info-circle ms-2" data-bs-toggle="tooltip" data-bs-placement="top" title='{{ form.hidden_name.description or "Docstring is not available" }}' ></i>
|
|
20
|
-
<a style="float: right" aria-label="Close" href="{{ url_for('control.hide_function', instrument=instrument, function=function) }}"><i class="bi bi-eye-slash-fill"></i></a>
|
|
21
|
-
<div class="form-control" style="border: none">
|
|
22
|
-
<form role="form" method='POST' name="{{function}}" id="{{function}}">
|
|
23
|
-
<div class="form-group">
|
|
24
|
-
{{ form.hidden_tag() }}
|
|
25
|
-
{% for field in form %}
|
|
26
|
-
{% if field.type not in ['CSRFTokenField', 'HiddenField'] %}
|
|
27
|
-
<div class="input-group mb-3">
|
|
28
|
-
<label class="input-group-text">{{ field.label.text }}</label>
|
|
29
|
-
{% if field.type == "SubmitField" %}
|
|
30
|
-
{{ field(class="btn btn-dark") }}
|
|
31
|
-
{% elif field.type == "BooleanField" %}
|
|
32
|
-
{{ field(class="form-check-input") }}
|
|
33
|
-
{% else %}
|
|
34
|
-
{{ field(class="form-control") }}
|
|
35
|
-
{% endif %}
|
|
36
|
-
</div>
|
|
37
|
-
{% endif %}
|
|
38
|
-
{% endfor %}
|
|
39
|
-
</div>
|
|
40
|
-
<div class="input-group mb-3">
|
|
41
|
-
<button type="submit" name="{{ function }}" id="{{ function }}" class="form-control" style="background-color: #a5cece;">{{format_name(function)}} </button>
|
|
42
|
-
|
|
43
|
-
</div>
|
|
44
|
-
|
|
45
|
-
</form>
|
|
46
|
-
</div>
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
{% endif %}
|
|
50
|
-
{% endfor %}
|
|
51
|
-
</div>
|
|
52
|
-
<div class="accordion accordion-flush" id="accordionActions" >
|
|
53
|
-
<div class="accordion-item">
|
|
54
|
-
<h4 class="accordion-header">
|
|
55
|
-
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#hidden">
|
|
56
|
-
Hidden functions
|
|
57
|
-
</button>
|
|
58
|
-
</h4>
|
|
59
|
-
</div>
|
|
60
|
-
<div id="hidden" class="accordion-collapse collapse" data-bs-parent="#accordionActions">
|
|
61
|
-
<div class="accordion-body">
|
|
62
|
-
{% set hidden_instrument = hidden.get(instrument, []) %}
|
|
63
|
-
{% for function in hidden_instrument %}
|
|
64
|
-
<div>
|
|
65
|
-
{{ function }} <a href="{{ url_for('control.remove_hidden', instrument=instrument, function=function) }}"><i class="bi bi-eye-fill"></i></a>
|
|
66
|
-
</div>
|
|
67
|
-
{% endfor %}
|
|
68
|
-
</div>
|
|
69
|
-
</div>
|
|
70
|
-
</div>
|
|
71
|
-
|
|
72
|
-
<script>
|
|
73
|
-
const saveOrderUrl = `{{ url_for('control.save_order', instrument=instrument) }}`;
|
|
74
|
-
const buttonIds = {{ session['card_order'][instrument] | tojson }};
|
|
75
|
-
</script>
|
|
76
|
-
<script src="{{ url_for('static', filename='js/sortable_card.js') }}"></script>
|
|
77
|
-
<script src="{{ url_for('static', filename='js/overlay.js') }}"></script>
|
|
78
|
-
{% endblock %}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
{% extends 'base.html' %}
|
|
2
|
-
{% block title %}IvoryOS | Devices{% endblock %}
|
|
3
|
-
{% block body %}
|
|
4
|
-
<div class="row">
|
|
5
|
-
{% if defined_variables %}
|
|
6
|
-
{% for instrument in defined_variables %}
|
|
7
|
-
<div class="col-xl-3 col-lg-4 col-md-6 mb-4 ">
|
|
8
|
-
<div class="bg-white rounded shadow-sm position-relative">
|
|
9
|
-
{% if deck %}
|
|
10
|
-
{# <a href="{{ url_for('control.disconnect', instrument=instrument) }}" class="stretched-link controller-card" style="float: right;color: red; position: relative;">Disconnect <i class="bi bi-x-square"></i></a>#}
|
|
11
|
-
<div class="p-4 controller-card">
|
|
12
|
-
<h5 class=""><a href="{{ url_for('control.controllers', instrument=instrument) }}" class="text-dark stretched-link">{{instrument.split(".")[1]}}</a></h5>
|
|
13
|
-
</div>
|
|
14
|
-
{% else %}
|
|
15
|
-
<div class="p-4 controller-card">
|
|
16
|
-
<h5 class=""><a href="{{ url_for('control.controllers', instrument=instrument) }}" class="text-dark stretched-link">{{instrument}}</a></h5>
|
|
17
|
-
</div>
|
|
18
|
-
{% endif %}
|
|
19
|
-
</div>
|
|
20
|
-
</div>
|
|
21
|
-
{% endfor %}
|
|
22
|
-
<div class="d-flex mb-3">
|
|
23
|
-
<a href="{{ url_for('control.download_proxy', filetype='proxy') }}" class="btn btn-outline-primary">
|
|
24
|
-
<i class="bi bi-download"></i> Download remote control script
|
|
25
|
-
</a>
|
|
26
|
-
</div>
|
|
27
|
-
{% if not deck %}
|
|
28
|
-
<div class="col-xl-3 col-lg-4 col-md-6 mb-4 ">
|
|
29
|
-
<div class="bg-white rounded shadow-sm position-relative">
|
|
30
|
-
<div class="p-4 controller-card" >
|
|
31
|
-
{% if deck %}
|
|
32
|
-
{# todo disconnect for imported deck #}
|
|
33
|
-
{# <h5> <a href="{{ url_for("disconnect") }}" class="stretched-link" style="color: orangered">Disconnect deck</a></h5>#}
|
|
34
|
-
{% else %}
|
|
35
|
-
<h5><a href="{{ url_for('control.new_controller') }}" style="color: orange" class="stretched-link">New connection</a></h5>
|
|
36
|
-
{% endif %}
|
|
37
|
-
</div>
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
{% endif %}
|
|
41
|
-
{% else %}
|
|
42
|
-
<div class="col-xl-3 col-lg-4 col-md-6 mb-4 ">
|
|
43
|
-
<div class="bg-white rounded shadow-sm position-relative">
|
|
44
|
-
<div class="p-4 controller-card" >
|
|
45
|
-
{% if deck %}
|
|
46
|
-
<h5><a data-bs-toggle="modal" href="#importModal" class="stretched-link"><i class="bi bi-folder-plus"></i> Import deck </a></h5>
|
|
47
|
-
{% else %}
|
|
48
|
-
<h5><a href="{{ url_for('control.new_controller') }}" style="color: orange" class="stretched-link">New connection</a></h5>
|
|
49
|
-
{% endif %}
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
</div>
|
|
53
|
-
{% endif %}
|
|
54
|
-
</div>
|
|
55
|
-
{% endblock %}
|