ivoryos 1.0.1__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.

Files changed (59) hide show
  1. {ivoryos-1.0.1/ivoryos.egg-info → ivoryos-1.0.3}/PKG-INFO +1 -1
  2. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/auth/auth.py +3 -3
  3. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/control/control.py +78 -43
  4. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/control/templates/control/controllers_home.html +7 -7
  5. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/database/database.py +62 -42
  6. ivoryos-1.0.1/ivoryos/routes/database/templates/database/experiment_database.html → ivoryos-1.0.3/ivoryos/routes/database/templates/database/scripts_database.html +27 -18
  7. ivoryos-1.0.1/ivoryos/routes/database/templates/database/workflow_run_database.html → ivoryos-1.0.3/ivoryos/routes/database/templates/database/workflow_database.html +27 -5
  8. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/design/design.py +113 -72
  9. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/client_proxy.py +1 -1
  10. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/script_runner.py +2 -1
  11. ivoryos-1.0.3/ivoryos/version.py +1 -0
  12. {ivoryos-1.0.1 → ivoryos-1.0.3/ivoryos.egg-info}/PKG-INFO +1 -1
  13. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos.egg-info/SOURCES.txt +3 -3
  14. ivoryos-1.0.1/ivoryos/version.py +0 -1
  15. {ivoryos-1.0.1 → ivoryos-1.0.3}/LICENSE +0 -0
  16. {ivoryos-1.0.1 → ivoryos-1.0.3}/MANIFEST.in +0 -0
  17. {ivoryos-1.0.1 → ivoryos-1.0.3}/README.md +0 -0
  18. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/__init__.py +0 -0
  19. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/config.py +0 -0
  20. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/__init__.py +0 -0
  21. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/auth/__init__.py +0 -0
  22. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/auth/templates/auth/login.html +0 -0
  23. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/auth/templates/auth/signup.html +0 -0
  24. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/control/__init__.py +0 -0
  25. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/control/templates/control/controllers.html +0 -0
  26. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/control/templates/control/controllers_new.html +0 -0
  27. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/database/__init__.py +0 -0
  28. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/database/templates/database/step_card.html +0 -0
  29. /ivoryos-1.0.1/ivoryos/routes/database/templates/database/experiment_step_view.html → /ivoryos-1.0.3/ivoryos/routes/database/templates/database/workflow_view.html +0 -0
  30. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/design/__init__.py +0 -0
  31. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/design/templates/design/experiment_builder.html +0 -0
  32. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/design/templates/design/experiment_run.html +0 -0
  33. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/main/__init__.py +0 -0
  34. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/main/main.py +0 -0
  35. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/main/templates/main/help.html +0 -0
  36. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/routes/main/templates/main/home.html +0 -0
  37. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/favicon.ico +0 -0
  38. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/gui_annotation/Slide1.png +0 -0
  39. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/gui_annotation/Slide2.PNG +0 -0
  40. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/js/overlay.js +0 -0
  41. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/js/socket_handler.js +0 -0
  42. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/js/sortable_card.js +0 -0
  43. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/js/sortable_design.js +0 -0
  44. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/logo.webp +0 -0
  45. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/static/style.css +0 -0
  46. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/templates/base.html +0 -0
  47. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/__init__.py +0 -0
  48. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/bo_campaign.py +0 -0
  49. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/db_models.py +0 -0
  50. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/form.py +0 -0
  51. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/global_config.py +0 -0
  52. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/llm_agent.py +0 -0
  53. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/task_runner.py +0 -0
  54. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos/utils/utils.py +0 -0
  55. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos.egg-info/dependency_links.txt +0 -0
  56. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos.egg-info/requires.txt +0 -0
  57. {ivoryos-1.0.1 → ivoryos-1.0.3}/ivoryos.egg-info/top_level.txt +0 -0
  58. {ivoryos-1.0.1 → ivoryos-1.0.3}/setup.cfg +0 -0
  59. {ivoryos-1.0.1 → 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.1
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
@@ -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,8 +1,10 @@
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
@@ -14,7 +16,7 @@ runner = TaskRunner()
14
16
  control = Blueprint('control', __name__, template_folder='templates/control')
15
17
 
16
18
 
17
- @control.route("/my_deck")
19
+ @control.route("/control/home/deck", strict_slashes=False)
18
20
  @login_required
19
21
  def deck_controllers():
20
22
  """
@@ -22,15 +24,15 @@ def deck_controllers():
22
24
 
23
25
  deck control home interface for listing all deck instruments
24
26
 
25
- .. http:get:: /my_deck
27
+ .. http:get:: /control/home/deck
26
28
  """
27
29
  deck_variables = global_config.deck_snapshot.keys()
28
30
  deck_list = utils.import_history(os.path.join(current_app.config["OUTPUT_FOLDER"], 'deck_history.txt'))
29
31
  return render_template('controllers_home.html', defined_variables=deck_variables, deck=True, history=deck_list)
30
32
 
31
33
 
32
- @control.route("/new_controller/")
33
- @control.route("/new_controller/<instrument>", methods=['GET', 'POST'])
34
+ @control.route("/control/new/", strict_slashes=False)
35
+ @control.route("/control/new/<instrument>", methods=['GET', 'POST'])
34
36
  @login_required
35
37
  def new_controller(instrument=None):
36
38
  """
@@ -38,12 +40,12 @@ def new_controller(instrument=None):
38
40
 
39
41
  interface for connecting a new <instrument>
40
42
 
41
- .. http:get:: /new_controller
43
+ .. http:get:: /control/new/
42
44
 
43
45
  :param instrument: instrument name
44
46
  :type instrument: str
45
47
 
46
- .. http:post:: /new_controller
48
+ .. http:post:: /control/new/
47
49
 
48
50
  :form device_name: module instance name (e.g. my_instance = MyClass())
49
51
  :form kwargs: dynamic module initialization kwargs fields
@@ -88,7 +90,7 @@ def new_controller(instrument=None):
88
90
  device=device, args=args, defined_variables=global_config.defined_variables)
89
91
 
90
92
 
91
- @control.route("/controllers")
93
+ @control.route("/control/home/temp", strict_slashes=False)
92
94
  @login_required
93
95
  def controllers_home():
94
96
  """
@@ -96,14 +98,15 @@ def controllers_home():
96
98
 
97
99
  temporarily connected devices home interface for listing all instruments
98
100
 
99
- .. http:get:: /controllers
101
+ .. http:get:: /control/home/temp
100
102
 
101
103
  """
102
104
  # defined_variables = parse_deck(deck)
103
- return render_template('controllers_home.html', defined_variables=global_config.defined_variables)
105
+ defined_variables = global_config.defined_variables.keys()
106
+ return render_template('controllers_home.html', defined_variables=defined_variables)
104
107
 
105
108
 
106
- @control.route("/controllers/<instrument>", methods=['GET', 'POST'])
109
+ @control.route("/control/<instrument>/methods", methods=['GET', 'POST'])
107
110
  @login_required
108
111
  def controllers(instrument: str):
109
112
  """
@@ -111,12 +114,12 @@ def controllers(instrument: str):
111
114
 
112
115
  control interface for selected <instrument>
113
116
 
114
- .. http:get:: /controllers
117
+ .. http:get:: /control/<instrument>/methods
115
118
 
116
119
  :param instrument: instrument name
117
120
  :type instrument: str
118
121
 
119
- .. http:post:: /controllers
122
+ .. http:post:: /control/<instrument>/methods
120
123
 
121
124
  :form hidden_name: function name (hidden field)
122
125
  :form kwargs: dynamic kwargs field
@@ -154,24 +157,50 @@ def controllers(instrument: str):
154
157
  flash(form.errors)
155
158
  return render_template('controllers.html', instrument=instrument, forms=forms, format_name=format_name)
156
159
 
160
+ @control.route("/control/download", strict_slashes=False)
161
+ @login_required
162
+ def download_proxy():
163
+ """
164
+ .. :quickref: Direct Control; download proxy interface
165
+
166
+ download proxy interface
157
167
 
158
- @control.route("/backend_control/<instrument>", methods=['POST'])
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'])
159
187
  def backend_control(instrument: str=None):
160
188
  """
161
189
  .. :quickref: Backend Control; backend control
162
190
 
163
191
  backend control through http requests
164
192
 
165
- .. http:get:: /backend_control
193
+ .. http:get:: /api/control/
166
194
 
167
195
  :param instrument: instrument name
168
196
  :type instrument: str
169
197
 
170
- .. http:post:: /backend_control
198
+ .. http:post:: /api/control/
171
199
 
172
200
  """
173
- inst_object = find_instrument_by_name(instrument)
174
- forms = create_form_from_module(sdl_module=inst_object, autofill=False, design=False)
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)
175
204
 
176
205
  if request.method == 'POST':
177
206
  method_name = request.form.get("hidden_name", None)
@@ -183,42 +212,48 @@ def backend_control(instrument: str=None):
183
212
  current_app=current_app._get_current_object())
184
213
  return jsonify(output), 200
185
214
 
186
-
187
- @control.route("/backend_control", methods=['GET'])
188
- def backend_client():
189
- """
190
- .. :quickref: Backend Control; get snapshot
191
-
192
- backend control through http requests
193
-
194
- .. http:get:: /backend_control
195
- """
196
- # Create a snapshot of the current deck configuration
197
215
  snapshot = global_config.deck_snapshot.copy()
198
-
199
216
  # Iterate through each instrument in the snapshot
200
217
  for instrument_key, instrument_data in snapshot.items():
201
218
  # Iterate through each function associated with the current instrument
202
219
  for function_key, function_data in instrument_data.items():
203
220
  # Convert the function signature to a string representation
204
221
  function_data['signature'] = str(function_data['signature'])
222
+ return jsonify(snapshot), 200
205
223
 
206
- json_output = jsonify(snapshot)
207
- return json_output, 200
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
208
243
 
209
244
 
210
- @control.route("/import_api", methods=['POST'])
245
+ @control.route("/control/import/module", methods=['POST'])
211
246
  def import_api():
212
247
  """
213
248
  .. :quickref: Advanced Features; Manually import API module(s)
214
249
 
215
250
  importing other Python modules
216
251
 
217
- .. http:post:: /import_api
252
+ .. http:post:: /control/import/module
218
253
 
219
254
  :form filepath: API (Python class) module filepath
220
255
 
221
- import the module and redirect to :http:get:`/ivoryos/new_controller/`
256
+ import the module and redirect to :http:get:`/ivoryos/control/new/`
222
257
 
223
258
  """
224
259
  filepath = request.form.get('filepath')
@@ -266,12 +301,12 @@ def import_api():
266
301
  # return redirect(url_for('control.deck_controllers'))
267
302
 
268
303
 
269
- @control.route("/import_deck", methods=['POST'])
304
+ @control.route("/control/import/deck", methods=['POST'])
270
305
  def import_deck():
271
306
  """
272
307
  .. :quickref: Advanced Features; Manually import a deck
273
308
 
274
- .. http:post:: /import_deck
309
+ .. http:post:: /control/import_deck
275
310
 
276
311
  :form filepath: deck module filepath
277
312
 
@@ -304,12 +339,12 @@ def import_deck():
304
339
  return redirect(back)
305
340
 
306
341
 
307
- @control.route('/save-order/<instrument>', methods=['POST'])
342
+ @control.route('/control/<instrument>/save-order', methods=['POST'])
308
343
  def save_order(instrument: str):
309
344
  """
310
345
  .. :quickref: Control Customization; Save functions' order
311
346
 
312
- .. http:post:: /save-order
347
+ .. http:post:: /control/save-order
313
348
 
314
349
  save function drag and drop order for the given <instrument>
315
350
 
@@ -320,12 +355,12 @@ def save_order(instrument: str):
320
355
  return '', 204
321
356
 
322
357
 
323
- @control.route('/hide_function/<instrument>/<function>')
358
+ @control.route('/control/<instrument>/<function>/hide')
324
359
  def hide_function(instrument, function):
325
360
  """
326
361
  .. :quickref: Control Customization; Hide function
327
362
 
328
- .. http:get:: /hide_function
363
+ .. http:get:: //control/<instrument>/<function>/hide
329
364
 
330
365
  Hide the given <instrument> and <function>
331
366
 
@@ -341,12 +376,12 @@ def hide_function(instrument, function):
341
376
  return redirect(back)
342
377
 
343
378
 
344
- @control.route('/remove_hidden/<instrument>/<function>')
379
+ @control.route('/control/<instrument>/<function>/unhide')
345
380
  def remove_hidden(instrument: str, function: str):
346
381
  """
347
382
  .. :quickref: Control Customization; Remove a hidden function
348
383
 
349
- .. http:get:: /remove_hidden
384
+ .. http:get:: /control/<instrument>/<function>/unhide
350
385
 
351
386
  Un-hide the given <instrument> and <function>
352
387
 
@@ -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
- {# {% if not deck %}#}
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
- {# {% 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 %}#}
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('design.download', filetype='proxy') }}" class="btn btn-outline-primary">
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>
@@ -8,21 +8,21 @@ database = Blueprint('database', __name__, template_folder='templates/database')
8
8
 
9
9
 
10
10
 
11
- @database.route("/edit_workflow/<workflow_name>")
11
+ @database.route("/database/scripts/edit/<script_name>")
12
12
  @login_required
13
- def edit_workflow(workflow_name):
13
+ def edit_workflow(script_name:str):
14
14
  """
15
- .. :quickref: Database; load workflow to canvas
15
+ .. :quickref: Database; load workflow script to canvas
16
16
 
17
17
  load the selected workflow to the design canvas
18
18
 
19
- .. http:get:: /edit_workflow/<workflow_name>
19
+ .. http:get:: /database/scripts/edit/<script_name>
20
20
 
21
- :param workflow_name: workflow name
22
- :type workflow_name: str
21
+ :param script_name: script name
22
+ :type script_name: str
23
23
  :status 302: redirect to :http:get:`/ivoryos/experiment/build/`
24
24
  """
25
- row = Script.query.get(workflow_name)
25
+ row = Script.query.get(script_name)
26
26
  script = Script(**row.as_dict())
27
27
  post_script_file(script)
28
28
  pseudo_name = session.get("pseudo_deck", "")
@@ -37,27 +37,27 @@ def edit_workflow(workflow_name):
37
37
  return redirect(url_for('design.experiment_builder'))
38
38
 
39
39
 
40
- @database.route("/delete_workflow/<workflow_name>")
40
+ @database.route("/database/scripts/delete/<script_name>")
41
41
  @login_required
42
- def delete_workflow(workflow_name: str):
42
+ def delete_workflow(script_name: str):
43
43
  """
44
44
  .. :quickref: Database; delete workflow
45
45
 
46
46
  delete workflow from database
47
47
 
48
- .. http:get:: /delete_workflow/<workflow_name>
48
+ .. http:get:: /database/scripts/delete/<script_name>
49
49
 
50
- :param workflow_name: workflow name
51
- :type workflow_name: str
52
- :status 302: redirect to :http:get:`/ivoryos/database/`
50
+ :param script_name: workflow name
51
+ :type script_name: str
52
+ :status 302: redirect to :http:get:`/ivoryos/database/scripts/`
53
53
 
54
54
  """
55
- Script.query.filter(Script.name == workflow_name).delete()
55
+ Script.query.filter(Script.name == script_name).delete()
56
56
  db.session.commit()
57
57
  return redirect(url_for('database.load_from_database'))
58
58
 
59
59
 
60
- @database.route("/publish")
60
+ @database.route("/database/scripts/save")
61
61
  @login_required
62
62
  def publish():
63
63
  """
@@ -65,7 +65,7 @@ def publish():
65
65
 
66
66
  save workflow to database
67
67
 
68
- .. http:get:: /publish
68
+ .. http:get:: /database/scripts/save
69
69
 
70
70
  :status 302: redirect to :http:get:`/ivoryos/experiment/build/`
71
71
  """
@@ -84,7 +84,7 @@ def publish():
84
84
  return redirect(url_for('design.experiment_builder'))
85
85
 
86
86
 
87
- @database.route("/finalize")
87
+ @database.route("/database/scripts/finalize")
88
88
  @login_required
89
89
  def finalize():
90
90
  """
@@ -106,8 +106,8 @@ def finalize():
106
106
  return redirect(url_for('design.experiment_builder'))
107
107
 
108
108
 
109
- @database.route("/database/", strict_slashes=False)
110
- @database.route("/database/<deck_name>")
109
+ @database.route("/database/scripts/", strict_slashes=False)
110
+ @database.route("/database/scripts/<deck_name>")
111
111
  @login_required
112
112
  def load_from_database(deck_name=None):
113
113
  """
@@ -115,7 +115,7 @@ def load_from_database(deck_name=None):
115
115
 
116
116
  backend control through http requests
117
117
 
118
- .. http:get:: /database/<deck_name>
118
+ .. http:get:: /database/scripts/<deck_name>
119
119
 
120
120
  :param deck_name: filter for deck name
121
121
  :type deck_name: str
@@ -135,19 +135,19 @@ def load_from_database(deck_name=None):
135
135
  page = request.args.get('page', default=1, type=int)
136
136
  per_page = 10
137
137
 
138
- workflows = query.paginate(page=page, per_page=per_page, error_out=False)
138
+ scripts = query.paginate(page=page, per_page=per_page, error_out=False)
139
139
  if request.accept_mimetypes.best_match(['application/json', 'text/html']) == 'application/json':
140
- workflows = query.all()
141
- workflow_names = [w.name for w in workflows]
140
+ scripts = query.all()
141
+ script_names = [script.name for script in scripts]
142
142
  return jsonify({
143
- "workflows": workflow_names,
143
+ "workflows": script_names,
144
144
  })
145
145
  else:
146
146
  # return HTML
147
- return render_template("experiment_database.html", workflows=workflows, deck_list=deck_list, deck_name=deck_name)
147
+ return render_template("scripts_database.html", scripts=scripts, deck_list=deck_list, deck_name=deck_name)
148
148
 
149
149
 
150
- @database.route("/edit_run_name", methods=['POST'])
150
+ @database.route("/database/scripts/rename", methods=['POST'])
151
151
  @login_required
152
152
  def edit_run_name():
153
153
  """
@@ -155,7 +155,7 @@ def edit_run_name():
155
155
 
156
156
  edit the name of the current workflow, won't save to the database
157
157
 
158
- .. http:post:: /edit_run_name
158
+ .. http:post:: database/scripts/rename
159
159
 
160
160
  : form run_name: new workflow name
161
161
  :status 302: redirect to :http:get:`/ivoryos/experiment/build/`
@@ -173,15 +173,15 @@ def edit_run_name():
173
173
  return redirect(url_for("design.experiment_builder"))
174
174
 
175
175
 
176
- @database.route("/save_as", methods=['POST'])
176
+ @database.route("/database/scripts/save_as", methods=['POST'])
177
177
  @login_required
178
178
  def save_as():
179
179
  """
180
180
  .. :quickref: Database; save the run name as
181
181
 
182
- save the workflow name as
182
+ save the current workflow script as
183
183
 
184
- .. http:post:: /save_as
184
+ .. http:post:: /database/scripts/save_as
185
185
 
186
186
  : form run_name: new workflow name
187
187
  :status 302: redirect to :http:get:`/ivoryos/experiment/build/`
@@ -203,9 +203,20 @@ def save_as():
203
203
  return redirect(url_for("design.experiment_builder"))
204
204
 
205
205
 
206
- @database.route('/workflow_runs')
206
+ # -----------------------------------------------------------
207
+ # ------------------ Workflow logs -----------------------
208
+ # -----------------------------------------------------------
209
+ @database.route('/database/workflows/')
207
210
  def list_workflows():
208
- query = WorkflowRun.query
211
+ """
212
+ .. :quickref: Database; list all workflow logs
213
+
214
+ list all workflow logs
215
+
216
+ .. http:get:: /database/workflows/
217
+
218
+ """
219
+ query = WorkflowRun.query.order_by(WorkflowRun.id.desc())
209
220
  search_term = request.args.get("keyword", None)
210
221
  if search_term:
211
222
  query = query.filter(WorkflowRun.name.like(f'%{search_term}%'))
@@ -219,11 +230,20 @@ def list_workflows():
219
230
  return jsonify({
220
231
  "workflow_data": workflow_data,
221
232
  })
222
- return render_template('workflow_run_database.html', workflows=workflows)
233
+ else:
234
+ return render_template('workflow_database.html', workflows=workflows)
223
235
 
224
236
 
225
- @database.route("/workflow_steps/<int:workflow_id>")
226
- def get_workflow_steps(workflow_id):
237
+ @database.route("/database/workflows/<int:workflow_id>")
238
+ def get_workflow_steps(workflow_id:int):
239
+ """
240
+ .. :quickref: Database; list all workflow logs
241
+
242
+ list all workflow logs
243
+
244
+ .. http:get:: /database/workflows/<int:workflow_id>
245
+
246
+ """
227
247
  workflow = WorkflowRun.query.get_or_404(workflow_id)
228
248
  steps = WorkflowStep.query.filter_by(workflow_id=workflow_id).order_by(WorkflowStep.start_time).all()
229
249
 
@@ -261,23 +281,23 @@ def get_workflow_steps(workflow_id):
261
281
  "workflow_info": workflow.as_dict(),
262
282
  "steps": grouped_json,
263
283
  })
264
-
265
- return render_template("experiment_step_view.html", workflow=workflow, grouped=grouped)
284
+ else:
285
+ return render_template("workflow_view.html", workflow=workflow, grouped=grouped)
266
286
 
267
287
 
268
- @database.route("/delete_workflow_data/<workflow_id>")
288
+ @database.route("/database/workflows/delete/<int:workflow_id>")
269
289
  @login_required
270
- def delete_workflow_data(workflow_id: str):
290
+ def delete_workflow_data(workflow_id: int):
271
291
  """
272
292
  .. :quickref: Database; delete experiment data from database
273
293
 
274
294
  delete workflow data from database
275
295
 
276
- .. http:get:: /delete_workflow_data/<workflow_id>
296
+ .. http:get:: /database/workflows/delete/<int:workflow_id>
277
297
 
278
298
  :param workflow_id: workflow id
279
- :type workflow_id: str
280
- :status 302: redirect to :http:get:`/ivoryos/workflow_runs/`
299
+ :type workflow_id: int
300
+ :status 302: redirect to :http:get:`/ivoryos/database/workflows/`
281
301
 
282
302
  """
283
303
  run = WorkflowRun.query.get(workflow_id)
@@ -35,19 +35,19 @@
35
35
  </tr>
36
36
  </thead>
37
37
  <tbody>
38
- {% for workflow in workflows %}
38
+ {% for script in scripts %}
39
39
  <tr>
40
- <td><a href="{{ url_for('database.edit_workflow', workflow_name=workflow.name) }}">{{ workflow.name }}</a></td>
41
- <td>{{ workflow.deck }}</td>
42
- <td>{{ workflow.status }}</td>
43
- <td>{{ workflow.time_created }}</td>
44
- <td>{{ workflow.last_modified }}</td>
45
- <td>{{ workflow.author }}</td>
40
+ <td><a href="{{ url_for('database.edit_workflow', script_name=script.name) }}">{{ script.name }}</a></td>
41
+ <td>{{ script.deck }}</td>
42
+ <td>{{ script.status }}</td>
43
+ <td>{{ script.time_created }}</td>
44
+ <td>{{ script.last_modified }}</td>
45
+ <td>{{ script.author }}</td>
46
46
  {# <td>{{ workflow.registered }}</td>#}
47
47
  <td>
48
48
  {#not workflow.status == "finalized" or#}
49
- {% if session['user'] == 'admin' or session['user'] == workflow.author %}
50
- <a href="{{ url_for('database.delete_workflow', workflow_name=workflow.name) }}">delete</a>
49
+ {% if session['user'] == 'admin' or session['user'] == script.author %}
50
+ <a href="{{ url_for('database.delete_workflow', script_name=script.name) }}">delete</a>
51
51
  {% else %}
52
52
  <a class="disabled-link">delete</a>
53
53
  {% endif %}
@@ -57,18 +57,27 @@
57
57
  </tbody>
58
58
  </table>
59
59
 
60
- {# paging#}
60
+ {# paging#}
61
61
  <div class="pagination justify-content-center">
62
- <div class="page-item {{ 'disabled' if not workflows.has_prev else '' }}">
63
- <a class="page-link" href="{{ url_for('database.load_from_database', page=workflows.prev_num) }}">Previous</a>
62
+ <div class="page-item {{ 'disabled' if not scripts.has_prev else '' }}">
63
+ <a class="page-link" href="{{ url_for('database.load_from_database', page=scripts.prev_num) }}">Previous</a>
64
64
  </div>
65
- {% for num in workflows.iter_pages() %}
66
- <div class="page-item">
67
- <a class="page-link {{ 'active' if num == workflows.page else '' }}" href="{{ url_for('database.load_from_database', page=num) }}">{{ num }}</a>
68
- </div>
65
+
66
+ {% for num in scripts.iter_pages() %}
67
+ {% if num %}
68
+ <div class="page-item {{ 'active' if num == scripts.page else '' }}">
69
+ <a class="page-link" href="{{ url_for('database.load_from_database', page=num) }}">{{ num }}</a>
70
+ </div>
71
+ {% else %}
72
+ <div class="page-item disabled">
73
+ <span class="page-link">…</span>
74
+ </div>
75
+ {% endif %}
69
76
  {% endfor %}
70
- <div class="page-item {{ 'disabled' if not workflows.has_next else '' }}">
71
- <a class="page-link" href="{{ url_for('database.load_from_database', page=workflows.next_num) }}">Next</a>
77
+
78
+ <div class="page-item {{ 'disabled' if not scripts.has_next else '' }}">
79
+ <a class="page-link" href="{{ url_for('database.load_from_database', page=scripts.next_num) }}">Next</a>
72
80
  </div>
73
81
  </div>
82
+
74
83
  {% endblock %}