ivoryos 1.1.0__py3-none-any.whl → 1.2.0b1__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.

Potentially problematic release.


This version of ivoryos might be problematic. Click here for more details.

Files changed (58) hide show
  1. ivoryos/__init__.py +12 -5
  2. ivoryos/routes/api/api.py +5 -58
  3. ivoryos/routes/control/control.py +46 -43
  4. ivoryos/routes/control/control_file.py +4 -4
  5. ivoryos/routes/control/control_new_device.py +10 -10
  6. ivoryos/routes/control/templates/controllers.html +38 -9
  7. ivoryos/routes/control/templates/controllers_new.html +1 -1
  8. ivoryos/routes/data/data.py +81 -60
  9. ivoryos/routes/data/templates/components/step_card.html +9 -3
  10. ivoryos/routes/data/templates/workflow_database.html +10 -4
  11. ivoryos/routes/design/design.py +306 -243
  12. ivoryos/routes/design/design_file.py +42 -31
  13. ivoryos/routes/design/design_step.py +132 -30
  14. ivoryos/routes/design/templates/components/action_form.html +4 -3
  15. ivoryos/routes/design/templates/components/{instrument_panel.html → actions_panel.html} +7 -5
  16. ivoryos/routes/design/templates/components/autofill_toggle.html +8 -12
  17. ivoryos/routes/design/templates/components/canvas.html +5 -14
  18. ivoryos/routes/design/templates/components/canvas_footer.html +5 -1
  19. ivoryos/routes/design/templates/components/canvas_header.html +36 -15
  20. ivoryos/routes/design/templates/components/canvas_main.html +34 -0
  21. ivoryos/routes/design/templates/components/deck_selector.html +8 -10
  22. ivoryos/routes/design/templates/components/edit_action_form.html +16 -7
  23. ivoryos/routes/design/templates/components/instruments_panel.html +66 -0
  24. ivoryos/routes/design/templates/components/modals/drop_modal.html +3 -5
  25. ivoryos/routes/design/templates/components/modals/new_script_modal.html +1 -2
  26. ivoryos/routes/design/templates/components/modals/rename_modal.html +5 -5
  27. ivoryos/routes/design/templates/components/modals/saveas_modal.html +2 -2
  28. ivoryos/routes/design/templates/components/python_code_overlay.html +26 -4
  29. ivoryos/routes/design/templates/components/sidebar.html +12 -13
  30. ivoryos/routes/design/templates/experiment_builder.html +20 -20
  31. ivoryos/routes/execute/execute.py +157 -13
  32. ivoryos/routes/execute/execute_file.py +38 -4
  33. ivoryos/routes/execute/templates/components/tab_bayesian.html +365 -113
  34. ivoryos/routes/execute/templates/components/tab_configuration.html +1 -1
  35. ivoryos/routes/library/library.py +70 -115
  36. ivoryos/routes/library/templates/library.html +27 -19
  37. ivoryos/static/js/action_handlers.js +213 -0
  38. ivoryos/static/js/db_delete.js +23 -0
  39. ivoryos/static/js/script_metadata.js +39 -0
  40. ivoryos/static/js/sortable_design.js +89 -56
  41. ivoryos/static/js/ui_state.js +113 -0
  42. ivoryos/utils/bo_campaign.py +137 -1
  43. ivoryos/utils/db_models.py +14 -5
  44. ivoryos/utils/form.py +4 -9
  45. ivoryos/utils/global_config.py +13 -1
  46. ivoryos/utils/script_runner.py +24 -5
  47. ivoryos/utils/serilize.py +203 -0
  48. ivoryos/utils/task_runner.py +4 -1
  49. ivoryos/version.py +1 -1
  50. {ivoryos-1.1.0.dist-info → ivoryos-1.2.0b1.dist-info}/METADATA +1 -1
  51. {ivoryos-1.1.0.dist-info → ivoryos-1.2.0b1.dist-info}/RECORD +54 -51
  52. ivoryos/routes/design/templates/components/action_list.html +0 -15
  53. ivoryos/routes/design/templates/components/operations_panel.html +0 -43
  54. ivoryos/routes/design/templates/components/script_info.html +0 -31
  55. ivoryos/routes/design/templates/components/scripts.html +0 -50
  56. {ivoryos-1.1.0.dist-info → ivoryos-1.2.0b1.dist-info}/LICENSE +0 -0
  57. {ivoryos-1.1.0.dist-info → ivoryos-1.2.0b1.dist-info}/WHEEL +0 -0
  58. {ivoryos-1.1.0.dist-info → ivoryos-1.2.0b1.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
- import csv
1
+
2
2
  import json
3
3
  import os
4
- from flask import Blueprint, send_file, request, flash, redirect, url_for, session, current_app
4
+ from flask import Blueprint, send_file, request, flash, redirect, url_for, current_app
5
5
  from werkzeug.utils import secure_filename
6
6
  from ivoryos.utils import utils
7
7
 
@@ -9,15 +9,17 @@ files = Blueprint('design_files', __name__)
9
9
 
10
10
 
11
11
 
12
- @files.route('/download/data/<filename>')
13
- def download_results(filename):
14
- """Download a workflow data file"""
15
- filepath = os.path.join(current_app.config["DATA_FOLDER"], filename)
16
- return send_file(os.path.abspath(filepath), as_attachment=True)
17
-
18
- @files.route('/upload/json', methods=['POST'])
12
+ @files.route('/files/script-json', methods=['POST'])
19
13
  def load_json():
20
- """Upload a workflow design file (.JSON)"""
14
+ """
15
+ .. :quickref: Workflow Design Ext; upload a workflow design file (.JSON)
16
+
17
+ .. http:post:: /files/script-json
18
+
19
+ :form file: workflow design JSON file
20
+ :status 302: load script json and then redirects to :http:get:`/ivoryos/design/draft`
21
+ """
22
+
21
23
  if request.method == "POST":
22
24
  f = request.files['file']
23
25
  if 'file' not in request.files:
@@ -29,29 +31,38 @@ def load_json():
29
31
  flash("Script file need to be JSON file")
30
32
  return redirect(url_for("design.experiment_builder"))
31
33
 
32
- @files.route('/download/script/<filetype>')
33
- def download(filetype):
34
- """Download a workflow design file"""
34
+ @files.route('/files/script-python')
35
+ def download_python():
36
+ """
37
+ .. :quickref: Workflow Design Ext; export a workflow design file (.py)
38
+
39
+ .. http:post:: /files/script-python
40
+
41
+ :status 302: redirects to :http:get:`/ivoryos/design/script/`
42
+ """
35
43
  script = utils.get_script_file()
36
44
  run_name = script.name if script.name else "untitled"
37
-
38
- if filetype == "configure":
39
- filepath = os.path.join(current_app.config['SCRIPT_FOLDER'], f"{run_name}_config.csv")
40
- with open(filepath, 'w', newline='') as f:
41
- writer = csv.writer(f)
42
- cfg, cfg_types = script.config("script")
43
- writer.writerow(cfg)
44
- writer.writerow(list(cfg_types.values()))
45
- elif filetype == "script":
46
- script.sort_actions()
47
- json_object = json.dumps(script.as_dict())
48
- filepath = os.path.join(current_app.config['SCRIPT_FOLDER'], f"{run_name}.json")
49
- with open(filepath, "w") as outfile:
50
- outfile.write(json_object)
51
- elif filetype == "python":
52
- filepath = os.path.join(current_app.config["SCRIPT_FOLDER"], f"{run_name}.py")
53
- else:
54
- return "Unsupported file type", 400
45
+ filepath = os.path.join(current_app.config["SCRIPT_FOLDER"], f"{run_name}.py")
46
+ return send_file(os.path.abspath(filepath), as_attachment=True)
47
+
48
+
49
+ @files.route('/files/script-json')
50
+ def download_json():
51
+ """
52
+ .. :quickref: Workflow Design Ext; export a workflow design file (.JSON)
53
+
54
+ .. http:post:: /files/script-json
55
+
56
+ :status 302: redirects to :http:get:`/ivoryos/design/script/`
57
+ """
58
+ script = utils.get_script_file()
59
+ run_name = script.name if script.name else "untitled"
60
+
61
+ script.sort_actions()
62
+ json_object = json.dumps(script.as_dict())
63
+ filepath = os.path.join(current_app.config['SCRIPT_FOLDER'], f"{run_name}.json")
64
+ with open(filepath, "w") as outfile:
65
+ outfile.write(json_object)
55
66
  return send_file(os.path.abspath(filepath), as_attachment=True)
56
67
 
57
68
 
@@ -1,43 +1,145 @@
1
- from flask import Blueprint, request, session, flash, redirect, url_for
1
+ from flask import Blueprint, request, session, flash, redirect, url_for, jsonify, render_template, current_app
2
+ from flask_login import login_required
3
+
2
4
  from ivoryos.utils import utils
3
- from ivoryos.utils.form import create_form_from_action
5
+ from ivoryos.utils.form import create_form_from_action, create_action_button
4
6
 
5
7
  steps = Blueprint('design_steps', __name__)
6
8
 
7
- @steps.route("/step/edit/<uuid>", methods=['GET', 'POST'])
8
- def edit_action(uuid: str):
9
- """Edit parameters of an action step on canvas"""
9
+
10
+ @steps.get("/draft/steps/<int:uuid>")
11
+ def get_step(uuid: int):
12
+ """
13
+ .. :quickref: Workflow Design Steps; get an action step editing form
14
+
15
+ .. http:get:: /steps/<int:uuid>
16
+
17
+ get the editing form for an action step
18
+
19
+ :param uuid: The step number id
20
+ :type uuid: int
21
+
22
+ :status 200: render template with action step form
23
+ """
10
24
  script = utils.get_script_file()
11
25
  action = script.find_by_uuid(uuid)
12
- session['edit_action'] = action
26
+ if request.method == 'GET':
27
+ # forms = create_form_from_action(action, script=script)
28
+ # session['edit_action'] = action
29
+ return render_template("components/edit_action_form.html",
30
+ action=action,
31
+ forms=create_form_from_action(action, script=script))
32
+
33
+
34
+ @steps.post("/draft/steps/<int:uuid>")
35
+ def save_step(uuid: int):
36
+ """
37
+ .. :quickref: Workflow Design Steps; save an action step on canvas
38
+
39
+ .. http:post:: /steps/<int:uuid>
13
40
 
14
- if request.method == "POST" and action is not None:
41
+ save the changes of an action step
42
+
43
+ :param uuid: The step number id
44
+ :type uuid: int
45
+
46
+ :status 200: render template with action step form
47
+ """
48
+ script = utils.get_script_file()
49
+ action = script.find_by_uuid(uuid)
50
+ if action is not None:
15
51
  forms = create_form_from_action(action, script=script)
16
- if "back" not in request.form:
17
- kwargs = {field.name: field.data for field in forms if field.name != 'csrf_token'}
18
- if forms and forms.validate_on_submit():
19
- save_as = kwargs.pop('return', '')
20
- kwargs = script.validate_variables(kwargs)
21
- script.update_by_uuid(uuid=uuid, args=kwargs, output=save_as)
22
- else:
23
- flash(forms.errors)
24
- session.pop('edit_action')
25
- return redirect(url_for('design.experiment_builder'))
26
-
27
- @steps.route("/step/delete/<id>")
28
- def delete_action(id: int):
29
- """Delete an action step on canvas"""
30
- back = request.referrer
52
+ kwargs = {field.name: field.data for field in forms if field.name != 'csrf_token'}
53
+ if forms and forms.validate_on_submit():
54
+ save_as = kwargs.pop('return', '')
55
+ kwargs = script.validate_variables(kwargs)
56
+ script.update_by_uuid(uuid=uuid, args=kwargs, output=save_as)
57
+ else:
58
+ flash(forms.errors)
59
+ utils.post_script_file(script)
60
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
61
+ session['python_code'] = exec_string
62
+ design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
63
+ return render_template("components/canvas_main.html",
64
+ script=script,
65
+ buttons_dict=design_buttons)
66
+
67
+ @steps.delete("/draft/steps/<int:uuid>")
68
+ def delete_step(uuid: int):
69
+ """
70
+ .. :quickref: Workflow Design Steps; delete an action step on canvas
71
+
72
+ .. http:delete:: /steps/<int:uuid>
73
+
74
+ delete an action step
75
+
76
+ :param uuid: The step number id
77
+ :type uuid: int
78
+
79
+ :status 200: render template with action step form
80
+ """
31
81
  script = utils.get_script_file()
32
- script.delete_action(id)
82
+ if request.method == 'DELETE':
83
+ script.delete_action(uuid)
33
84
  utils.post_script_file(script)
34
- return redirect(back)
85
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
86
+ session['python_code'] = exec_string
87
+ design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
88
+ return render_template("components/canvas_main.html",
89
+ script=script,
90
+ buttons_dict=design_buttons)
91
+
92
+
93
+ @steps.route("/draft/steps/<int:uuid>/duplicate", methods=["POST"], strict_slashes=False,)
94
+ def duplicate_action(uuid: int):
95
+ """
96
+ .. :quickref: Workflow Design Steps; duplicate an action step on canvas
97
+
98
+ .. http:post:: /draft/steps/<int:uuid>/duplicate
35
99
 
36
- @steps.route("/step/duplicate/<id>")
37
- def duplicate_action(id: int):
38
- """Duplicate an action step on canvas"""
39
- back = request.referrer
100
+ :param uuid: The step number uuid
101
+ :type uuid: int
102
+
103
+ :status 200: render new design script template
104
+ """
105
+
106
+ # back = request.referrer
40
107
  script = utils.get_script_file()
41
- script.duplicate_action(id)
108
+ script.duplicate_action(uuid)
42
109
  utils.post_script_file(script)
43
- return redirect(back)
110
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
111
+ session['python_code'] = exec_string
112
+ design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
113
+
114
+ return render_template("components/canvas_main.html",
115
+ script=script,
116
+ buttons_dict=design_buttons)
117
+
118
+
119
+ @steps.route("/draft/steps/order", methods=['POST'])
120
+ @login_required
121
+ def update_list():
122
+ """
123
+ .. :quickref: Workflow Design Steps; update the order of steps in the design canvas when reordering steps.
124
+
125
+ .. http:post:: /draft/steps/order
126
+
127
+ Update the order of steps in the design canvas when reordering steps.
128
+
129
+ :form order: A comma-separated string representing the new order of steps.
130
+ :status 200: Successfully updated the order of steps.
131
+ """
132
+ order = request.form['order']
133
+ script = utils.get_script_file()
134
+ script.currently_editing_order = order.split(",", len(script.currently_editing_script))
135
+ script.sort_actions()
136
+
137
+ utils.post_script_file(script)
138
+ exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
139
+ session['python_code'] = exec_string
140
+
141
+ # Return the updated canvas HTML instead of JSON
142
+ design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
143
+ return render_template("components/canvas_main.html",
144
+ script=script,
145
+ buttons_dict=design_buttons)
@@ -6,18 +6,19 @@
6
6
  data-bs-target="#{{name}}" aria-expanded="false"
7
7
  aria-controls="collapseExample"
8
8
  data-action="{{ name }}">
9
- {{ format_name(name) }}
9
+ {{ name | format_name }}
10
10
  </button>
11
11
  </h2>
12
12
  <div id="{{name}}" class="accordion-collapse collapse" data-bs-parent="#accordionActions">
13
13
  <div class="accordion-body">
14
- <form role="form" method='POST' name="add" id="add-{{name}}">
14
+ <form role="form" method='POST' action="{{ url_for('design.methods_handler', instrument=instrument) }}"
15
+ name="add" id="add-{{name}}" onsubmit="addMethodToDesign(event, this); return false;">
15
16
  <div class="form-group">
16
17
  {{ form.hidden_tag() }}
17
18
  {% for field in form %}
18
19
  {% if field.type not in ['CSRFTokenField', 'HiddenField'] %}
19
20
  <div class="input-group mb-3">
20
- <label class="input-group-text">{{ field.label.text }}</label>
21
+ <label class="input-group-text">{{ field.label.text | format_name }}</label>
21
22
  {% if field.type == "SubmitField" %}
22
23
  {{ field(class="btn btn-dark") }}
23
24
  {% elif field.type == "BooleanField" %}
@@ -1,8 +1,13 @@
1
1
  {# Instrument panel component #}
2
2
  <div>
3
3
  <div class="d-flex justify-content-between align-items-center " style="margin-bottom: 1vh;margin-top: 1vh;">
4
- <a class="btn btn-primary" role="button" type="button" href="{{url_for('design.experiment_builder')}}"><i class="bi bi-arrow-return-left"></i></a>
5
- {{ format_name(instrument) }}
4
+ {# <a class="btn btn-primary" role="button" type="button" href="{{url_for('design.experiment_builder')}}"><i class="bi bi-arrow-return-left"></i></a>#}
5
+ <a type="button"
6
+ data-get-url="{{ url_for('design.get_operation_sidebar') }}"
7
+ onclick="updateInstrumentPanel(this)">
8
+ <i class="bi bi-arrow-return-left"></i>
9
+ </a>
10
+ {{ instrument | format_name }}
6
11
  </div>
7
12
 
8
13
  {% if script.editing_type == "script" %}
@@ -12,9 +17,6 @@
12
17
 
13
18
  {# accordion for instrument #}
14
19
  <div class="accordion accordion-flush" id="accordionActions" >
15
- {% if use_llm and not instrument == "flow_control" %}
16
- {% include 'components/text_to_code_panel.html' %}
17
- {% endif %}
18
20
 
19
21
  {% for name, form in forms.items() %}
20
22
  {% include 'components/action_form.html' %}
@@ -1,14 +1,10 @@
1
1
  {# Autofill toggle component #}
2
2
  <div class="d-flex justify-content-between align-items-center " style="margin-bottom: 1vh;margin-top: 1vh;">
3
- <div></div>
4
- <form role="form" method='POST' name="autoFill" id="autoFill">
5
- <div class="form-check form-switch">
6
- <input type="hidden" id="autofill" name="autofill" value="temp_value">
7
- <input class="form-check-input" type="checkbox" id="autoFillCheck" name="autoFillCheck" onchange="document.getElementById('autoFill').submit();"
8
- value="temp_value"
9
- {{ "checked" if session["autofill"] else "" }}>
10
- <label class="form-check-label" for="autoFillCheck">Auto fill</label>
11
- </div>
12
- <button type="submit" class="btn btn-default" style="display: none;">Auto fill </button>
13
- </form>
14
- </div>
3
+ <div class="form-check form-switch" data-instrument="{{ instrument }}">
4
+ {# <input type="hidden" id="autofill" name="autofill" value="temp_value">#}
5
+ <input class="form-check-input" type="checkbox" id="autoFillCheck" name="autoFillCheck" onchange="toggleAutoFill()"
6
+ value="temp_value"
7
+ {{ "checked" if session["autofill"] else "" }}>
8
+ <label class="form-check-label" for="autoFillCheck">Auto fill</label>
9
+ </div>
10
+ </div>
@@ -1,14 +1,5 @@
1
- {# Canvas component for experiment builder #}
2
- <div class="col-md-9 scroll-column">
3
- {% include 'components/canvas_header.html' %}
4
-
5
- <div class="canvas-wrapper position-relative">
6
- <div class="canvas" droppable="true">
7
- {% include 'components/script_info.html' %}
8
- {% include 'components/action_list.html' %}
9
- {% include 'components/python_code_overlay.html' %}
10
- </div>
11
- </div>
12
-
13
- {% include 'components/canvas_footer.html' %}
14
- </div>
1
+ {% include 'components/canvas_header.html' %}
2
+ <div class="canvas canvas-action-wrapper position-relative" id="canvas-action-wrapper" droppable="true">
3
+ {% include 'components/canvas_main.html' %}
4
+ </div>
5
+ {% include 'components/canvas_footer.html' %}
@@ -1,5 +1,9 @@
1
1
  {# Canvas footer component #}
2
2
  <div>
3
- <a class="btn btn-dark {{ 'disabled' if not script.name or script.status == "finalized" else ''}}" href="{{url_for('library.publish')}}">Quick Save</a>
3
+ <a class="btn btn-dark {{ 'disabled' if not script.name or script.status == "finalized" else '' }}"
4
+ href="#" data-post-url="{{ url_for('library.workflow_script', script_name=script.name or 'untitled') }}"
5
+ onclick="saveWorkflow(this); return false;">
6
+ Quick Save
7
+ </a>
4
8
  <a class="btn btn-dark " href="{{ url_for('execute.experiment_run') }}">Compile and Run</a>
5
9
  </div>
@@ -10,7 +10,7 @@
10
10
  <div class="btn-toolbar" role="toolbar">
11
11
  <button class="btn btn-primary btn-sm me-1" data-bs-toggle="modal" data-bs-target="#newScriptModal">New</button>
12
12
  <button class="btn btn-secondary btn-sm me-1" data-bs-toggle="modal" data-bs-target="#jsonModal">Import</button>
13
- <a class="btn btn-secondary btn-sm me-1" href="{{url_for('design.design_files.download', filetype='script')}}">Export</a>
13
+ <a class="btn btn-secondary btn-sm me-1" href="{{url_for('design.design_files.download_json', filetype='script')}}">Export</a>
14
14
  <button class="btn btn-secondary btn-sm me-1" data-bs-toggle="modal" data-bs-target="#saveasModal">Save as</button>
15
15
  <div class="btn-group">
16
16
  <button class="btn btn-outline-secondary btn-sm dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">More</button>
@@ -18,12 +18,18 @@
18
18
  <li>
19
19
  <button class="dropdown-item" data-bs-toggle="modal" data-bs-target="#renameModal">Rename</button>
20
20
  </li>
21
+ {% if script.name %}
21
22
  <li>
22
- <a class="dropdown-item {% if not script.name or script.status == 'finalized' %}disabled{% endif %}" href="{% if script.name and script.status != 'finalized' %}{{url_for('library.publish')}}{% else %}#{% endif %}">Save</a>
23
+ <a class="dropdown-item {{ 'disabled' if not script.name or script.status == "finalized" else '' }}"
24
+ href="#" data-post-url="{{ url_for('library.workflow_script', script_name=script.name) }}"
25
+ onclick="saveWorkflow(this); return false;">
26
+ Save
27
+ </a>
23
28
  </li>
29
+ {% endif %}
24
30
  {% if not script.status == 'finalized' %}
25
31
  <li>
26
- <a class="dropdown-item" href="{{url_for('library.finalize')}}">Disable editing</a>
32
+ <a class="dropdown-item" onclick="lockScriptEditing()">Disable editing</a>
27
33
  </li>
28
34
  {% endif %}
29
35
  </ul>
@@ -34,21 +40,36 @@
34
40
  <!-- Tabs for Info/Prep/Experiment/Cleanup below header -->
35
41
  <div class="d-flex align-items-center mt-2 justify-content-between">
36
42
  <ul class="nav nav-tabs mb-0">
37
- <li class="nav-item"><a class="{{'nav-link active' if script.editing_type=='prep' else 'nav-link'}}" href="{{url_for('design.toggle_script_type', stype='prep') }}">Prep</a></li>
38
- <li class="nav-item"><a class="{{'nav-link active' if script.editing_type=='script' else 'nav-link'}}" href="{{url_for('design.toggle_script_type', stype='script') }}">Experiment</a></li>
39
- <li class="nav-item"><a class="{{'nav-link active' if script.editing_type=='cleanup' else 'nav-link'}}" href="{{url_for('design.toggle_script_type', stype='cleanup') }}">Clean up</a></li>
43
+ <li class="nav-item">
44
+ <a class="nav-link {{ 'active' if script.editing_type == 'prep' else '' }}"
45
+ href="#" onclick="setScriptPhase('prep')">
46
+ Prep
47
+ </a>
48
+ </li>
49
+ <li class="nav-item">
50
+ <a class="nav-link {{ 'active' if script.editing_type == 'script' else '' }}"
51
+ href="#" onclick="setScriptPhase('script')">
52
+ Experiment
53
+ </a>
54
+ </li>
55
+ <li class="nav-item">
56
+ <a class="nav-link {{ 'active' if script.editing_type == 'cleanup' else '' }}"
57
+ href="#" onclick="setScriptPhase('cleanup')">
58
+ Clean up
59
+ </a>
60
+ </li>
40
61
  </ul>
62
+
41
63
  <div class="d-flex align-items-center ms-auto">
42
- <form method="POST" action="{{ url_for('design.toggle_show_code') }}" class="mb-0 me-3">
43
- <div class="form-check form-switch">
44
- <input class="form-check-input" type="checkbox" id="showPythonCodeSwitch" name="show_code"
45
- onchange="this.form.submit()" {% if session.get('show_code') %}checked{% endif %}>
46
- <label class="form-check-label" for="showPythonCodeSwitch">Show Code</label>
47
- </div>
48
- </form>
49
64
  <div class="form-check form-switch">
50
- <input class="form-check-input" type="checkbox" id="toggleLineNumbers" onchange="toggleLineNumbers()">
51
- <label class="form-check-label" for="toggleLineNumbers">Show Line Numbers</label>
65
+ <input class="form-check-input" type="checkbox" id="showPythonCodeSwitch" name="show_code"
66
+ onchange="toggleCodeOverlay()" {% if session.get('show_code') %}checked{% endif %}>
67
+ <label class="form-check-label" for="showPythonCodeSwitch">Preview code</label>
52
68
  </div>
69
+ {# <div class="form-check form-switch">#}
70
+ {# <input class="form-check-input" type="checkbox" id="toggleLineNumbers"#}
71
+ {# onchange="toggleLineNumbers()">#}
72
+ {# <label class="form-check-label" for="toggleLineNumbers">Show Line Numbers</label>#}
73
+ {# </div>#}
53
74
  </div>
54
75
  </div>
@@ -0,0 +1,34 @@
1
+ {# Action list component #}
2
+
3
+ <!-- partials/canvas_content.html -->
4
+
5
+
6
+ <div class="list-group" id="list" style="margin-top: 20px">
7
+ <ul class="reorder">
8
+
9
+ {% if script.editing_type == "prep" %}
10
+ {% set buttons = buttons_dict["prep"] or [] %}
11
+ {% elif script.editing_type == "script" %}
12
+ {% set buttons = buttons_dict["script"] or [] %}
13
+ {% elif script.editing_type == "cleanup" %}
14
+ {% set buttons = buttons_dict["cleanup"] or [] %}
15
+ {% endif %}
16
+
17
+ {% for button in buttons %}
18
+ <li id="{{ button['id'] }}" style="list-style-type: none;">
19
+ <span class="line-number d-none">{{ button['id'] }}.</span>
20
+ <a href="#" onclick="editAction('{{ button['uuid'] }}'); return false;" type="button" class="btn btn-light" style="{{ button['style'] }}">{{ button['label'] }}</a>
21
+ {% if not button["instrument"] in ["if","while","repeat"] %}
22
+ <button onclick="duplicateAction('{{ button['id'] }}')" type="button" class="btn btn-light"><span class="bi bi-copy"></span></button>
23
+
24
+ {% endif %}
25
+ <button onclick="deleteAction('{{ button['id'] }}')" type="button" class="btn btn-light">
26
+ <span class="bi bi-trash"></span>
27
+ </button>
28
+ </li>
29
+ {% endfor %}
30
+ </ul>
31
+ </div>
32
+ <div class="python-code-wrapper" id="python-code-wrapper">
33
+ {% include 'components/python_code_overlay.html' %}
34
+ </div>
@@ -1,12 +1,10 @@
1
1
  {# Deck selector component #}
2
- <form id="select-deck" method="POST" action="{{ url_for('design.temp.import_pseudo') }}" enctype="multipart/form-data">
3
- <div class="input-group mb-3">
4
- <select class="form-select" name="pkl_name" id="pkl_name" required onchange="document.getElementById('select-deck').submit();">
5
- <option {{ '' if 'pseudo_deck' in session else 'selected' }} disabled hidden style="overflow-wrap: break-word;" name="pkl_name" id="pkl_name" value=""> -- choose deck --</option>
6
- {% for connection in history %}
7
- <option {{ 'selected' if session['pseudo_deck']==connection else '' }} style="overflow-wrap: break-word;" name="pkl_name" id="pkl_name" value="{{connection}}">{{connection.split('.')[0]}}</option>
8
- {% endfor %}
9
- </select>
10
- </div>
11
- </form>
2
+ <div class="input-group mb-3">
3
+ <select class="form-select" name="deck_name" id="deck_name" required onchange="changeDeck(this.value);">
4
+ <option {{ '' if 'pseudo_deck' in session else 'selected' }} disabled hidden style="overflow-wrap: break-word;" name="deck_name" id="deck_name" value=""> -- choose deck --</option>
5
+ {% for connection in history %}
6
+ <option {{ 'selected' if session['pseudo_deck']==connection else '' }} style="overflow-wrap: break-word;" name="deck_name" id="deck_name" value="{{connection}}">{{connection.split('.')[0]}}</option>
7
+ {% endfor %}
8
+ </select>
9
+ </div>
12
10
  <hr>
@@ -1,13 +1,23 @@
1
1
  {# Edit action form component #}
2
- {% with action = session["edit_action"] %}
3
- <h5> {{ format_name(action['action']) }} </h5>
4
- <form role="form" method='POST' name="{{instrument}}" action="{{ url_for('design.design_steps.edit_action', uuid=session["edit_action"]['uuid']) }}">
2
+ <div style="margin-bottom: 1vh;margin-top: 1vh;">
3
+ <a type="button"
4
+ data-get-url="{{ url_for('design.get_operation_sidebar') }}"
5
+ onclick="updateInstrumentPanel(this)">
6
+ <i class="bi bi-arrow-return-left"></i>
7
+ </a>
8
+ </div>
9
+ <h5> {{ action['action'] | format_name }} </h5>
10
+ <form role="form" method='POST' name="{{instrument}}"
11
+ action="{{ url_for('design.design_steps.get_step', uuid=action['uuid']) }}"
12
+ onsubmit="submitEditForm(event); return false;">
5
13
  {% if not action['args'] == None %}
6
14
  <div class="form-group">
7
15
  {% if not action['args'].__class__.__name__ == 'dict' %}
8
16
  <div class="input-group mb-3">
9
17
  <label class="input-group-text">{{ action['action'] }}</label>
10
- <input class="form-control" type="text" id="arg" name="arg" placeholder="{{ action['arg_types']}}" value="{{ action['args'] }}" aria-labelledby="variableHelpBlock">
18
+ <input class="form-control" type="text" id="arg" name="arg"
19
+ placeholder="{{ action['arg_types']}}" value="{{ action['args'] }}"
20
+ aria-labelledby="variableHelpBlock">
11
21
  </div>
12
22
  {% else %}
13
23
  {{ forms.hidden_tag() }}
@@ -23,7 +33,6 @@
23
33
  {% endif %}
24
34
  </div>
25
35
  {% endif %}
26
- <button class="btn btn-primary" type="submit">Save</button>
27
- <button class="btn btn-primary" type="submit" name="back" id="back" value="back">Back</button>
36
+ <button type="submit" class="btn btn-primary">Save</button>
37
+ <button type="button" class="btn btn-primary" id="back">Back</button>
28
38
  </form>
29
- {% endwith %}
@@ -0,0 +1,66 @@
1
+ {# Operations panel component #}
2
+ <div style="margin-bottom: 4vh;"></div>
3
+ <div class="accordion accordion-flush">
4
+ <div class="accordion-item design-control">
5
+ <h5 class="accordion-header">
6
+ <button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#flow" role="button" aria-expanded="false" aria-controls="collapseExample">
7
+ Flow control
8
+ </button>
9
+ </h5>
10
+ <div class="accordion-collapse collapse show" id="flow">
11
+ <ul class="list-group">
12
+ <button class="list-group-item list-group-item-action"
13
+ type="button"
14
+ name="device"
15
+ value="flow_control"
16
+ data-get-url="{{ url_for('design.get_operation_sidebar', instrument='flow_control') }}"
17
+ onclick="updateInstrumentPanel(this)">
18
+ Flow control
19
+ </button>
20
+ </ul>
21
+ </div>
22
+ <h5 class="accordion-header">
23
+ <button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#deck" role="button" aria-expanded="false" aria-controls="collapseExample">
24
+ Instruments
25
+ </button>
26
+ </h5>
27
+ <div class="accordion-collapse collapse show" id="deck">
28
+ <ul class="list-group">
29
+ {% for instrument in defined_variables %}
30
+ <button class="list-group-item list-group-item-action"
31
+ type="button"
32
+ name="device"
33
+ value="{{instrument}}"
34
+ data-get-url="{{ url_for('design.get_operation_sidebar', instrument=instrument) }}"
35
+ onclick="updateInstrumentPanel(this)">
36
+ {{ instrument | format_name }}
37
+ </button>
38
+ {% endfor %}
39
+ </ul>
40
+ </div>
41
+ </div>
42
+
43
+ {% if local_variables %}
44
+ <div class="accordion-item design-control">
45
+ <h5 class="accordion-header">
46
+ <button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#local" role="button" aria-expanded="false" aria-controls="collapseExample">
47
+ Temp instruments
48
+ </button>
49
+ </h5>
50
+ <div class="accordion-collapse collapse show" id="local">
51
+ <ul class="list-group">
52
+ {% for instrument in local_variables %}
53
+ <button class="list-group-item list-group-item-action"
54
+ type="button"
55
+ name="device"
56
+ value="{{instrument}}"
57
+ data-get-url="{{ url_for('design.get_operation_sidebar', instrument=instrument) }}"
58
+ onclick="updateInstrumentPanel(this)">
59
+ {{instrument}}
60
+ </button>
61
+ {% endfor%}
62
+ </ul>
63
+ </div>
64
+ </div>
65
+ {% endif %}
66
+ </div>