ivoryos 1.0.0__tar.gz → 1.0.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ivoryos might be problematic. Click here for more details.
- {ivoryos-1.0.0/ivoryos.egg-info → ivoryos-1.0.3}/PKG-INFO +3 -3
- {ivoryos-1.0.0 → ivoryos-1.0.3}/README.md +2 -2
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/auth/auth.py +3 -3
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/control/control.py +89 -60
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/control/templates/control/controllers_home.html +7 -7
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/database/database.py +98 -39
- ivoryos-1.0.0/ivoryos/routes/database/templates/database/experiment_database.html → ivoryos-1.0.3/ivoryos/routes/database/templates/database/scripts_database.html +27 -18
- ivoryos-1.0.0/ivoryos/routes/database/templates/database/workflow_run_database.html → ivoryos-1.0.3/ivoryos/routes/database/templates/database/workflow_database.html +27 -5
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/design/design.py +215 -78
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/design/templates/design/experiment_run.html +62 -123
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/js/socket_handler.js +13 -8
- ivoryos-1.0.3/ivoryos/utils/bo_campaign.py +87 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/client_proxy.py +1 -1
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/db_models.py +27 -7
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/global_config.py +16 -7
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/script_runner.py +56 -40
- ivoryos-1.0.3/ivoryos/utils/task_runner.py +81 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/utils.py +0 -68
- ivoryos-1.0.3/ivoryos/version.py +1 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3/ivoryos.egg-info}/PKG-INFO +3 -3
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos.egg-info/SOURCES.txt +5 -3
- ivoryos-1.0.0/ivoryos/version.py +0 -1
- {ivoryos-1.0.0 → ivoryos-1.0.3}/LICENSE +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/MANIFEST.in +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/config.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/auth/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/auth/templates/auth/login.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/auth/templates/auth/signup.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/control/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/control/templates/control/controllers.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/control/templates/control/controllers_new.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/database/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/database/templates/database/step_card.html +0 -0
- /ivoryos-1.0.0/ivoryos/routes/database/templates/database/experiment_step_view.html → /ivoryos-1.0.3/ivoryos/routes/database/templates/database/workflow_view.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/design/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/design/templates/design/experiment_builder.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/main/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/main/main.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/main/templates/main/help.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/main/templates/main/home.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/favicon.ico +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/gui_annotation/Slide1.png +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/gui_annotation/Slide2.PNG +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/js/overlay.js +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/js/sortable_card.js +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/js/sortable_design.js +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/logo.webp +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/static/style.css +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/templates/base.html +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/__init__.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/form.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/utils/llm_agent.py +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos.egg-info/dependency_links.txt +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos.egg-info/requires.txt +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos.egg-info/top_level.txt +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/setup.cfg +0 -0
- {ivoryos-1.0.0 → ivoryos-1.0.3}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: ivoryos
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.3
|
|
4
4
|
Summary: an open-source Python package enabling Self-Driving Labs (SDLs) interoperability
|
|
5
5
|
Home-page: https://gitlab.com/heingroup/ivoryos
|
|
6
6
|
Author: Ivory Zhang
|
|
@@ -14,8 +14,8 @@ License-File: LICENSE
|
|
|
14
14
|
[](https://pypi.org/project/ivoryos/)
|
|
15
15
|

|
|
16
16
|
[](https://youtu.be/dFfJv9I2-1g)
|
|
17
|
-
[](https://www.nature.com/articles/s41467-025-60514-w)
|
|
18
|
+
[](https://discord.gg/AX5P9EdGVX)
|
|
19
19
|
|
|
20
20
|

|
|
21
21
|
# ivoryOS: interoperable Web UI for self-driving laboratories (SDLs)
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
[](https://pypi.org/project/ivoryos/)
|
|
3
3
|

|
|
4
4
|
[](https://youtu.be/dFfJv9I2-1g)
|
|
5
|
-
[](https://www.nature.com/articles/s41467-025-60514-w)
|
|
6
|
+
[](https://discord.gg/AX5P9EdGVX)
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|
# ivoryOS: interoperable Web UI for self-driving laboratories (SDLs)
|
|
@@ -9,7 +9,7 @@ login_manager = LoginManager()
|
|
|
9
9
|
auth = Blueprint('auth', __name__, template_folder='templates/auth')
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
@auth.route('/login', methods=['GET', 'POST'])
|
|
12
|
+
@auth.route('/auth/login', methods=['GET', 'POST'])
|
|
13
13
|
def login():
|
|
14
14
|
"""
|
|
15
15
|
.. :quickref: User; login user
|
|
@@ -50,7 +50,7 @@ def login():
|
|
|
50
50
|
return render_template('login.html')
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
@auth.route('/signup', methods=['GET', 'POST'])
|
|
53
|
+
@auth.route('/auth/signup', methods=['GET', 'POST'])
|
|
54
54
|
def signup():
|
|
55
55
|
"""
|
|
56
56
|
.. :quickref: User; signup for a new account
|
|
@@ -82,7 +82,7 @@ def signup():
|
|
|
82
82
|
return render_template('signup.html')
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
@auth.route("/logout")
|
|
85
|
+
@auth.route("/auth/logout")
|
|
86
86
|
@login_required
|
|
87
87
|
def logout():
|
|
88
88
|
"""
|
|
@@ -1,18 +1,22 @@
|
|
|
1
1
|
import os
|
|
2
2
|
|
|
3
|
-
from flask import Blueprint, redirect, url_for, flash, request, render_template, session, current_app, jsonify
|
|
3
|
+
from flask import Blueprint, redirect, url_for, flash, request, render_template, session, current_app, jsonify, \
|
|
4
|
+
send_file
|
|
4
5
|
from flask_login import login_required
|
|
5
6
|
|
|
7
|
+
from ivoryos.utils.client_proxy import export_to_python, create_function
|
|
6
8
|
from ivoryos.utils.global_config import GlobalConfig
|
|
7
9
|
from ivoryos.utils import utils
|
|
8
10
|
from ivoryos.utils.form import create_form_from_module, format_name
|
|
11
|
+
from ivoryos.utils.task_runner import TaskRunner
|
|
9
12
|
|
|
10
13
|
global_config = GlobalConfig()
|
|
14
|
+
runner = TaskRunner()
|
|
11
15
|
|
|
12
16
|
control = Blueprint('control', __name__, template_folder='templates/control')
|
|
13
17
|
|
|
14
18
|
|
|
15
|
-
@control.route("/
|
|
19
|
+
@control.route("/control/home/deck", strict_slashes=False)
|
|
16
20
|
@login_required
|
|
17
21
|
def deck_controllers():
|
|
18
22
|
"""
|
|
@@ -20,15 +24,15 @@ def deck_controllers():
|
|
|
20
24
|
|
|
21
25
|
deck control home interface for listing all deck instruments
|
|
22
26
|
|
|
23
|
-
.. http:get:: /
|
|
27
|
+
.. http:get:: /control/home/deck
|
|
24
28
|
"""
|
|
25
29
|
deck_variables = global_config.deck_snapshot.keys()
|
|
26
30
|
deck_list = utils.import_history(os.path.join(current_app.config["OUTPUT_FOLDER"], 'deck_history.txt'))
|
|
27
31
|
return render_template('controllers_home.html', defined_variables=deck_variables, deck=True, history=deck_list)
|
|
28
32
|
|
|
29
33
|
|
|
30
|
-
@control.route("/
|
|
31
|
-
@control.route("/
|
|
34
|
+
@control.route("/control/new/", strict_slashes=False)
|
|
35
|
+
@control.route("/control/new/<instrument>", methods=['GET', 'POST'])
|
|
32
36
|
@login_required
|
|
33
37
|
def new_controller(instrument=None):
|
|
34
38
|
"""
|
|
@@ -36,12 +40,12 @@ def new_controller(instrument=None):
|
|
|
36
40
|
|
|
37
41
|
interface for connecting a new <instrument>
|
|
38
42
|
|
|
39
|
-
.. http:get:: /
|
|
43
|
+
.. http:get:: /control/new/
|
|
40
44
|
|
|
41
45
|
:param instrument: instrument name
|
|
42
46
|
:type instrument: str
|
|
43
47
|
|
|
44
|
-
.. http:post:: /
|
|
48
|
+
.. http:post:: /control/new/
|
|
45
49
|
|
|
46
50
|
:form device_name: module instance name (e.g. my_instance = MyClass())
|
|
47
51
|
:form kwargs: dynamic module initialization kwargs fields
|
|
@@ -86,7 +90,7 @@ def new_controller(instrument=None):
|
|
|
86
90
|
device=device, args=args, defined_variables=global_config.defined_variables)
|
|
87
91
|
|
|
88
92
|
|
|
89
|
-
@control.route("/
|
|
93
|
+
@control.route("/control/home/temp", strict_slashes=False)
|
|
90
94
|
@login_required
|
|
91
95
|
def controllers_home():
|
|
92
96
|
"""
|
|
@@ -94,14 +98,15 @@ def controllers_home():
|
|
|
94
98
|
|
|
95
99
|
temporarily connected devices home interface for listing all instruments
|
|
96
100
|
|
|
97
|
-
.. http:get:: /
|
|
101
|
+
.. http:get:: /control/home/temp
|
|
98
102
|
|
|
99
103
|
"""
|
|
100
104
|
# defined_variables = parse_deck(deck)
|
|
101
|
-
|
|
105
|
+
defined_variables = global_config.defined_variables.keys()
|
|
106
|
+
return render_template('controllers_home.html', defined_variables=defined_variables)
|
|
102
107
|
|
|
103
108
|
|
|
104
|
-
@control.route("/
|
|
109
|
+
@control.route("/control/<instrument>/methods", methods=['GET', 'POST'])
|
|
105
110
|
@login_required
|
|
106
111
|
def controllers(instrument: str):
|
|
107
112
|
"""
|
|
@@ -109,12 +114,12 @@ def controllers(instrument: str):
|
|
|
109
114
|
|
|
110
115
|
control interface for selected <instrument>
|
|
111
116
|
|
|
112
|
-
.. http:get:: /
|
|
117
|
+
.. http:get:: /control/<instrument>/methods
|
|
113
118
|
|
|
114
119
|
:param instrument: instrument name
|
|
115
120
|
:type instrument: str
|
|
116
121
|
|
|
117
|
-
.. http:post:: /
|
|
122
|
+
.. http:post:: /control/<instrument>/methods
|
|
118
123
|
|
|
119
124
|
:form hidden_name: function name (hidden field)
|
|
120
125
|
:form kwargs: dynamic kwargs field
|
|
@@ -142,7 +147,9 @@ def controllers(instrument: str):
|
|
|
142
147
|
if form and form.validate_on_submit():
|
|
143
148
|
try:
|
|
144
149
|
kwargs.pop("hidden_name")
|
|
145
|
-
output =
|
|
150
|
+
output = runner.run_single_step(instrument, method_name, kwargs, wait=True,
|
|
151
|
+
current_app=current_app._get_current_object())
|
|
152
|
+
# output = function_executable(**kwargs)
|
|
146
153
|
flash(f"\nRun Success! Output value: {output}.")
|
|
147
154
|
except Exception as e:
|
|
148
155
|
flash(e.__str__())
|
|
@@ -150,81 +157,103 @@ def controllers(instrument: str):
|
|
|
150
157
|
flash(form.errors)
|
|
151
158
|
return render_template('controllers.html', instrument=instrument, forms=forms, format_name=format_name)
|
|
152
159
|
|
|
160
|
+
@control.route("/control/download", strict_slashes=False)
|
|
161
|
+
@login_required
|
|
162
|
+
def download_proxy():
|
|
163
|
+
"""
|
|
164
|
+
.. :quickref: Direct Control; download proxy interface
|
|
153
165
|
|
|
154
|
-
|
|
166
|
+
download proxy interface
|
|
167
|
+
|
|
168
|
+
.. http:get:: /control/download
|
|
169
|
+
"""
|
|
170
|
+
snapshot = global_config.deck_snapshot.copy()
|
|
171
|
+
class_definitions = {}
|
|
172
|
+
# Iterate through each instrument in the snapshot
|
|
173
|
+
for instrument_key, instrument_data in snapshot.items():
|
|
174
|
+
# Iterate through each function associated with the current instrument
|
|
175
|
+
for function_key, function_data in instrument_data.items():
|
|
176
|
+
# Convert the function signature to a string representation
|
|
177
|
+
function_data['signature'] = str(function_data['signature'])
|
|
178
|
+
class_name = instrument_key.split('.')[-1] # Extracting the class name from the path
|
|
179
|
+
class_definitions[class_name.capitalize()] = create_function(request.url_root, class_name, instrument_data)
|
|
180
|
+
# Export the generated class definitions to a .py script
|
|
181
|
+
export_to_python(class_definitions, current_app.config["OUTPUT_FOLDER"])
|
|
182
|
+
filepath = os.path.join(current_app.config["OUTPUT_FOLDER"], "generated_proxy.py")
|
|
183
|
+
return send_file(os.path.abspath(filepath), as_attachment=True)
|
|
184
|
+
|
|
185
|
+
@control.route("/api/control/", strict_slashes=False, methods=['GET'])
|
|
186
|
+
@control.route("/api/control/<instrument>", methods=['POST'])
|
|
155
187
|
def backend_control(instrument: str=None):
|
|
156
188
|
"""
|
|
157
189
|
.. :quickref: Backend Control; backend control
|
|
158
190
|
|
|
159
191
|
backend control through http requests
|
|
160
192
|
|
|
161
|
-
.. http:get:: /
|
|
193
|
+
.. http:get:: /api/control/
|
|
162
194
|
|
|
163
195
|
:param instrument: instrument name
|
|
164
196
|
:type instrument: str
|
|
165
197
|
|
|
166
|
-
.. http:post:: /
|
|
198
|
+
.. http:post:: /api/control/
|
|
167
199
|
|
|
168
200
|
"""
|
|
169
|
-
|
|
170
|
-
|
|
201
|
+
if instrument:
|
|
202
|
+
inst_object = find_instrument_by_name(instrument)
|
|
203
|
+
forms = create_form_from_module(sdl_module=inst_object, autofill=False, design=False)
|
|
171
204
|
|
|
172
205
|
if request.method == 'POST':
|
|
173
|
-
|
|
174
|
-
method_name = all_kwargs.pop("hidden_name", None)
|
|
175
|
-
# if method_name is not None:
|
|
206
|
+
method_name = request.form.get("hidden_name", None)
|
|
176
207
|
form = forms.get(method_name, None)
|
|
177
|
-
kwargs = {field.name: field.data for field in form if field.name != 'csrf_token'}
|
|
178
|
-
function_executable = getattr(inst_object, method_name)
|
|
179
208
|
if form:
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
except Exception as e:
|
|
186
|
-
json_output = jsonify(e.__str__())
|
|
187
|
-
return json_output, 400
|
|
188
|
-
else:
|
|
189
|
-
return "instrument not exist", 400
|
|
190
|
-
return json_output, 200
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
@control.route("/backend_control", methods=['GET'])
|
|
194
|
-
def backend_client():
|
|
195
|
-
"""
|
|
196
|
-
.. :quickref: Backend Control; get snapshot
|
|
197
|
-
|
|
198
|
-
backend control through http requests
|
|
209
|
+
kwargs = {field.name: field.data for field in form if field.name not in ['csrf_token', 'hidden_name']}
|
|
210
|
+
wait = request.form.get("hidden_wait", "true") == "true"
|
|
211
|
+
output = runner.run_single_step(component=instrument, method=method_name, kwargs=kwargs, wait=wait,
|
|
212
|
+
current_app=current_app._get_current_object())
|
|
213
|
+
return jsonify(output), 200
|
|
199
214
|
|
|
200
|
-
.. http:get:: /backend_control
|
|
201
|
-
"""
|
|
202
|
-
# Create a snapshot of the current deck configuration
|
|
203
215
|
snapshot = global_config.deck_snapshot.copy()
|
|
204
|
-
|
|
205
216
|
# Iterate through each instrument in the snapshot
|
|
206
217
|
for instrument_key, instrument_data in snapshot.items():
|
|
207
218
|
# Iterate through each function associated with the current instrument
|
|
208
219
|
for function_key, function_data in instrument_data.items():
|
|
209
220
|
# Convert the function signature to a string representation
|
|
210
221
|
function_data['signature'] = str(function_data['signature'])
|
|
222
|
+
return jsonify(snapshot), 200
|
|
211
223
|
|
|
212
|
-
|
|
213
|
-
|
|
224
|
+
# @control.route("/api/control", strict_slashes=False, methods=['GET'])
|
|
225
|
+
# def backend_client():
|
|
226
|
+
# """
|
|
227
|
+
# .. :quickref: Backend Control; get snapshot
|
|
228
|
+
#
|
|
229
|
+
# backend control through http requests
|
|
230
|
+
#
|
|
231
|
+
# .. http:get:: /api/control/summary
|
|
232
|
+
# """
|
|
233
|
+
# # Create a snapshot of the current deck configuration
|
|
234
|
+
# snapshot = global_config.deck_snapshot.copy()
|
|
235
|
+
#
|
|
236
|
+
# # Iterate through each instrument in the snapshot
|
|
237
|
+
# for instrument_key, instrument_data in snapshot.items():
|
|
238
|
+
# # Iterate through each function associated with the current instrument
|
|
239
|
+
# for function_key, function_data in instrument_data.items():
|
|
240
|
+
# # Convert the function signature to a string representation
|
|
241
|
+
# function_data['signature'] = str(function_data['signature'])
|
|
242
|
+
# return jsonify(snapshot), 200
|
|
214
243
|
|
|
215
244
|
|
|
216
|
-
@control.route("/
|
|
245
|
+
@control.route("/control/import/module", methods=['POST'])
|
|
217
246
|
def import_api():
|
|
218
247
|
"""
|
|
219
248
|
.. :quickref: Advanced Features; Manually import API module(s)
|
|
220
249
|
|
|
221
250
|
importing other Python modules
|
|
222
251
|
|
|
223
|
-
.. http:post:: /
|
|
252
|
+
.. http:post:: /control/import/module
|
|
224
253
|
|
|
225
254
|
:form filepath: API (Python class) module filepath
|
|
226
255
|
|
|
227
|
-
import the module and redirect to :http:get:`/ivoryos/
|
|
256
|
+
import the module and redirect to :http:get:`/ivoryos/control/new/`
|
|
228
257
|
|
|
229
258
|
"""
|
|
230
259
|
filepath = request.form.get('filepath')
|
|
@@ -272,12 +301,12 @@ def import_api():
|
|
|
272
301
|
# return redirect(url_for('control.deck_controllers'))
|
|
273
302
|
|
|
274
303
|
|
|
275
|
-
@control.route("/
|
|
304
|
+
@control.route("/control/import/deck", methods=['POST'])
|
|
276
305
|
def import_deck():
|
|
277
306
|
"""
|
|
278
307
|
.. :quickref: Advanced Features; Manually import a deck
|
|
279
308
|
|
|
280
|
-
.. http:post:: /import_deck
|
|
309
|
+
.. http:post:: /control/import_deck
|
|
281
310
|
|
|
282
311
|
:form filepath: deck module filepath
|
|
283
312
|
|
|
@@ -310,12 +339,12 @@ def import_deck():
|
|
|
310
339
|
return redirect(back)
|
|
311
340
|
|
|
312
341
|
|
|
313
|
-
@control.route('/save-order
|
|
342
|
+
@control.route('/control/<instrument>/save-order', methods=['POST'])
|
|
314
343
|
def save_order(instrument: str):
|
|
315
344
|
"""
|
|
316
345
|
.. :quickref: Control Customization; Save functions' order
|
|
317
346
|
|
|
318
|
-
.. http:post:: /save-order
|
|
347
|
+
.. http:post:: /control/save-order
|
|
319
348
|
|
|
320
349
|
save function drag and drop order for the given <instrument>
|
|
321
350
|
|
|
@@ -326,12 +355,12 @@ def save_order(instrument: str):
|
|
|
326
355
|
return '', 204
|
|
327
356
|
|
|
328
357
|
|
|
329
|
-
@control.route('/
|
|
358
|
+
@control.route('/control/<instrument>/<function>/hide')
|
|
330
359
|
def hide_function(instrument, function):
|
|
331
360
|
"""
|
|
332
361
|
.. :quickref: Control Customization; Hide function
|
|
333
362
|
|
|
334
|
-
.. http:get::
|
|
363
|
+
.. http:get:: //control/<instrument>/<function>/hide
|
|
335
364
|
|
|
336
365
|
Hide the given <instrument> and <function>
|
|
337
366
|
|
|
@@ -347,12 +376,12 @@ def hide_function(instrument, function):
|
|
|
347
376
|
return redirect(back)
|
|
348
377
|
|
|
349
378
|
|
|
350
|
-
@control.route('/
|
|
379
|
+
@control.route('/control/<instrument>/<function>/unhide')
|
|
351
380
|
def remove_hidden(instrument: str, function: str):
|
|
352
381
|
"""
|
|
353
382
|
.. :quickref: Control Customization; Remove a hidden function
|
|
354
383
|
|
|
355
|
-
.. http:get:: /
|
|
384
|
+
.. http:get:: /control/<instrument>/<function>/unhide
|
|
356
385
|
|
|
357
386
|
Un-hide the given <instrument> and <function>
|
|
358
387
|
|
{ivoryos-1.0.0 → ivoryos-1.0.3}/ivoryos/routes/control/templates/control/controllers_home.html
RENAMED
|
@@ -6,21 +6,21 @@
|
|
|
6
6
|
{% for instrument in defined_variables %}
|
|
7
7
|
<div class="col-xl-3 col-lg-4 col-md-6 mb-4 ">
|
|
8
8
|
<div class="bg-white rounded shadow-sm position-relative">
|
|
9
|
-
|
|
9
|
+
{% if deck %}
|
|
10
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
11
|
<div class="p-4 controller-card">
|
|
12
12
|
<h5 class=""><a href="{{ url_for('control.controllers', instrument=instrument) }}" class="text-dark stretched-link">{{instrument.split(".")[1]}}</a></h5>
|
|
13
13
|
</div>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
19
|
</div>
|
|
20
20
|
</div>
|
|
21
21
|
{% endfor %}
|
|
22
22
|
<div class="d-flex mb-3">
|
|
23
|
-
<a href="{{ url_for('
|
|
23
|
+
<a href="{{ url_for('control.download_proxy', filetype='proxy') }}" class="btn btn-outline-primary">
|
|
24
24
|
<i class="bi bi-download"></i> Download remote control script
|
|
25
25
|
</a>
|
|
26
26
|
</div>
|