ivoryos 1.2.5__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 +16 -246
- ivoryos/app.py +154 -0
- ivoryos/optimizer/ax_optimizer.py +55 -28
- ivoryos/optimizer/base_optimizer.py +20 -1
- ivoryos/optimizer/baybe_optimizer.py +27 -17
- ivoryos/optimizer/nimo_optimizer.py +173 -0
- ivoryos/optimizer/registry.py +3 -1
- ivoryos/routes/auth/auth.py +35 -8
- ivoryos/routes/auth/templates/change_password.html +32 -0
- ivoryos/routes/control/control.py +58 -28
- ivoryos/routes/control/control_file.py +12 -15
- ivoryos/routes/control/control_new_device.py +21 -11
- ivoryos/routes/control/templates/controllers.html +27 -0
- ivoryos/routes/control/utils.py +2 -0
- ivoryos/routes/data/data.py +110 -44
- ivoryos/routes/data/templates/components/step_card.html +78 -13
- ivoryos/routes/data/templates/workflow_view.html +343 -113
- ivoryos/routes/design/design.py +59 -10
- ivoryos/routes/design/design_file.py +3 -3
- ivoryos/routes/design/design_step.py +43 -17
- ivoryos/routes/design/templates/components/action_form.html +2 -2
- ivoryos/routes/design/templates/components/canvas_main.html +6 -1
- ivoryos/routes/design/templates/components/edit_action_form.html +18 -3
- ivoryos/routes/design/templates/components/info_modal.html +318 -0
- ivoryos/routes/design/templates/components/instruments_panel.html +23 -1
- ivoryos/routes/design/templates/components/python_code_overlay.html +27 -10
- ivoryos/routes/design/templates/experiment_builder.html +3 -0
- ivoryos/routes/execute/execute.py +82 -22
- ivoryos/routes/execute/templates/components/logging_panel.html +50 -25
- ivoryos/routes/execute/templates/components/run_tabs.html +45 -2
- ivoryos/routes/execute/templates/components/tab_bayesian.html +447 -325
- ivoryos/routes/execute/templates/components/tab_configuration.html +303 -18
- ivoryos/routes/execute/templates/components/tab_repeat.html +6 -2
- ivoryos/routes/execute/templates/experiment_run.html +0 -264
- ivoryos/routes/library/library.py +9 -11
- ivoryos/routes/main/main.py +30 -2
- ivoryos/server.py +180 -0
- ivoryos/socket_handlers.py +1 -1
- ivoryos/static/ivoryos_logo.png +0 -0
- ivoryos/static/js/action_handlers.js +259 -88
- ivoryos/static/js/socket_handler.js +40 -5
- ivoryos/static/js/sortable_design.js +29 -11
- ivoryos/templates/base.html +61 -2
- ivoryos/utils/bo_campaign.py +18 -17
- ivoryos/utils/client_proxy.py +267 -36
- ivoryos/utils/db_models.py +286 -60
- ivoryos/utils/decorators.py +34 -0
- ivoryos/utils/form.py +52 -19
- ivoryos/utils/global_config.py +21 -0
- ivoryos/utils/nest_script.py +314 -0
- ivoryos/utils/py_to_json.py +80 -10
- ivoryos/utils/script_runner.py +573 -189
- ivoryos/utils/task_runner.py +69 -22
- ivoryos/utils/utils.py +48 -5
- ivoryos/version.py +1 -1
- {ivoryos-1.2.5.dist-info → ivoryos-1.4.4.dist-info}/METADATA +109 -47
- ivoryos-1.4.4.dist-info/RECORD +119 -0
- ivoryos-1.4.4.dist-info/top_level.txt +3 -0
- tests/__init__.py +0 -0
- tests/conftest.py +133 -0
- tests/integration/__init__.py +0 -0
- tests/integration/test_route_auth.py +80 -0
- tests/integration/test_route_control.py +94 -0
- tests/integration/test_route_database.py +61 -0
- tests/integration/test_route_design.py +36 -0
- tests/integration/test_route_main.py +35 -0
- tests/integration/test_sockets.py +26 -0
- tests/unit/test_type_conversion.py +42 -0
- tests/unit/test_util.py +3 -0
- ivoryos/routes/api/api.py +0 -56
- ivoryos-1.2.5.dist-info/RECORD +0 -100
- ivoryos-1.2.5.dist-info/top_level.txt +0 -1
- {ivoryos-1.2.5.dist-info → ivoryos-1.4.4.dist-info}/WHEEL +0 -0
- {ivoryos-1.2.5.dist-info → ivoryos-1.4.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -12,7 +12,7 @@ def get_step(uuid: int):
|
|
|
12
12
|
"""
|
|
13
13
|
.. :quickref: Workflow Design Steps; get an action step editing form
|
|
14
14
|
|
|
15
|
-
.. http:get:: /steps/<int:uuid>
|
|
15
|
+
.. http:get:: /draft/steps/<int:uuid>
|
|
16
16
|
|
|
17
17
|
get the editing form for an action step
|
|
18
18
|
|
|
@@ -23,12 +23,16 @@ def get_step(uuid: int):
|
|
|
23
23
|
"""
|
|
24
24
|
script = utils.get_script_file()
|
|
25
25
|
action = script.find_by_uuid(uuid)
|
|
26
|
-
if
|
|
27
|
-
|
|
26
|
+
if action is None:
|
|
27
|
+
return jsonify({"warning": "Step not found, please refresh the page."}), 404
|
|
28
|
+
|
|
29
|
+
elif request.method == 'GET':
|
|
30
|
+
forms = create_form_from_action(action, script=script)
|
|
28
31
|
# session['edit_action'] = action
|
|
29
32
|
return render_template("components/edit_action_form.html",
|
|
30
33
|
action=action,
|
|
31
|
-
forms=
|
|
34
|
+
forms=forms)
|
|
35
|
+
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
@steps.post("/draft/steps/<int:uuid>")
|
|
@@ -36,7 +40,7 @@ def save_step(uuid: int):
|
|
|
36
40
|
"""
|
|
37
41
|
.. :quickref: Workflow Design Steps; save an action step on canvas
|
|
38
42
|
|
|
39
|
-
.. http:post:: /steps/<int:uuid>
|
|
43
|
+
.. http:post:: /draft/steps/<int:uuid>
|
|
40
44
|
|
|
41
45
|
save the changes of an action step
|
|
42
46
|
|
|
@@ -47,29 +51,36 @@ def save_step(uuid: int):
|
|
|
47
51
|
"""
|
|
48
52
|
script = utils.get_script_file()
|
|
49
53
|
action = script.find_by_uuid(uuid)
|
|
54
|
+
warning = None
|
|
50
55
|
if action is not None:
|
|
51
56
|
forms = create_form_from_action(action, script=script)
|
|
52
57
|
kwargs = {field.name: field.data for field in forms if field.name != 'csrf_token'}
|
|
53
58
|
if forms and forms.validate_on_submit():
|
|
54
59
|
save_as = kwargs.pop('return', '')
|
|
60
|
+
batch_action = kwargs.pop('batch_action', False)
|
|
55
61
|
kwargs = script.validate_variables(kwargs)
|
|
56
|
-
script.update_by_uuid(uuid=uuid, args=kwargs, output=save_as)
|
|
62
|
+
script.update_by_uuid(uuid=uuid, args=kwargs, output=save_as, batch_action=batch_action)
|
|
57
63
|
else:
|
|
58
|
-
|
|
64
|
+
warning = f"Compilation failed: {str(forms.errors)}"
|
|
59
65
|
utils.post_script_file(script)
|
|
60
|
-
|
|
66
|
+
try:
|
|
67
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
68
|
+
except Exception as e:
|
|
69
|
+
exec_string = {}
|
|
70
|
+
warning = f"Compilation failed: {str(e)}"
|
|
61
71
|
session['python_code'] = exec_string
|
|
62
72
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
63
73
|
return render_template("components/canvas_main.html",
|
|
64
|
-
|
|
65
|
-
|
|
74
|
+
script=script,
|
|
75
|
+
buttons_dict=design_buttons,
|
|
76
|
+
warning=warning)
|
|
66
77
|
|
|
67
78
|
@steps.delete("/draft/steps/<int:uuid>")
|
|
68
79
|
def delete_step(uuid: int):
|
|
69
80
|
"""
|
|
70
81
|
.. :quickref: Workflow Design Steps; delete an action step on canvas
|
|
71
82
|
|
|
72
|
-
.. http:delete:: /steps/<int:uuid>
|
|
83
|
+
.. http:delete:: /draft/steps/<int:uuid>
|
|
73
84
|
|
|
74
85
|
delete an action step
|
|
75
86
|
|
|
@@ -82,12 +93,17 @@ def delete_step(uuid: int):
|
|
|
82
93
|
if request.method == 'DELETE':
|
|
83
94
|
script.delete_action(uuid)
|
|
84
95
|
utils.post_script_file(script)
|
|
85
|
-
|
|
96
|
+
warning = None
|
|
97
|
+
try:
|
|
98
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
99
|
+
except Exception as e:
|
|
100
|
+
exec_string = {}
|
|
101
|
+
warning = f"Compilation failed: {str(e)}"
|
|
86
102
|
session['python_code'] = exec_string
|
|
87
103
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
88
104
|
return render_template("components/canvas_main.html",
|
|
89
105
|
script=script,
|
|
90
|
-
buttons_dict=design_buttons)
|
|
106
|
+
buttons_dict=design_buttons, warning=warning)
|
|
91
107
|
|
|
92
108
|
|
|
93
109
|
@steps.route("/draft/steps/<int:uuid>/duplicate", methods=["POST"], strict_slashes=False,)
|
|
@@ -107,13 +123,18 @@ def duplicate_action(uuid: int):
|
|
|
107
123
|
script = utils.get_script_file()
|
|
108
124
|
script.duplicate_action(uuid)
|
|
109
125
|
utils.post_script_file(script)
|
|
110
|
-
|
|
126
|
+
warning = None
|
|
127
|
+
try:
|
|
128
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
129
|
+
except Exception as e:
|
|
130
|
+
exec_string = {}
|
|
131
|
+
warning = f"Compilation failed: {str(e)}"
|
|
111
132
|
session['python_code'] = exec_string
|
|
112
133
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
113
134
|
|
|
114
135
|
return render_template("components/canvas_main.html",
|
|
115
136
|
script=script,
|
|
116
|
-
buttons_dict=design_buttons)
|
|
137
|
+
buttons_dict=design_buttons, warning=warning)
|
|
117
138
|
|
|
118
139
|
|
|
119
140
|
@steps.route("/draft/steps/order", methods=['POST'])
|
|
@@ -133,13 +154,18 @@ def update_list():
|
|
|
133
154
|
script = utils.get_script_file()
|
|
134
155
|
script.currently_editing_order = order.split(",", len(script.currently_editing_script))
|
|
135
156
|
script.sort_actions()
|
|
157
|
+
warning = None
|
|
136
158
|
|
|
137
159
|
utils.post_script_file(script)
|
|
138
|
-
|
|
160
|
+
try:
|
|
161
|
+
exec_string = script.compile(current_app.config['SCRIPT_FOLDER'])
|
|
162
|
+
except Exception as e:
|
|
163
|
+
exec_string = {}
|
|
164
|
+
warning = f"Compilation failed: {str(e)}"
|
|
139
165
|
session['python_code'] = exec_string
|
|
140
166
|
|
|
141
167
|
# Return the updated canvas HTML instead of JSON
|
|
142
168
|
design_buttons = {stype: create_action_button(script, stype) for stype in script.stypes}
|
|
143
169
|
return render_template("components/canvas_main.html",
|
|
144
170
|
script=script,
|
|
145
|
-
buttons_dict=design_buttons)
|
|
171
|
+
buttons_dict=design_buttons, warning=warning)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{# Action form component #}
|
|
2
|
-
<div class="accordion-item design-control"
|
|
3
|
-
<h2 class="accordion-header">
|
|
2
|
+
<div class="accordion-item design-control">
|
|
3
|
+
<h2 class="accordion-header" >
|
|
4
4
|
<button class="accordion-button collapsed draggable-action"
|
|
5
5
|
type="button" data-bs-toggle="collapse"
|
|
6
6
|
data-bs-target="#{{name}}" aria-expanded="false"
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
<i class="bi bi-arrow-return-left"></i>
|
|
7
7
|
</a>
|
|
8
8
|
</div>
|
|
9
|
+
{% if action %}
|
|
9
10
|
<h5> {{ action['action'] | format_name }} </h5>
|
|
10
11
|
<form role="form" method='POST' name="{{instrument}}"
|
|
11
12
|
action="{{ url_for('design.design_steps.get_step', uuid=action['uuid']) }}"
|
|
@@ -22,11 +23,24 @@
|
|
|
22
23
|
{% else %}
|
|
23
24
|
{{ forms.hidden_tag() }}
|
|
24
25
|
{% for field in forms %}
|
|
26
|
+
|
|
25
27
|
{% if field.type not in ['CSRFTokenField'] %}
|
|
26
28
|
<div class="input-group mb-3">
|
|
27
|
-
<label class="input-group-text">{{ field.label.text }}</label>
|
|
28
|
-
{
|
|
29
|
-
|
|
29
|
+
<label class="input-group-text">{{ field.label.text | format_name }}</label>
|
|
30
|
+
{% if field.type == "BooleanField" %}
|
|
31
|
+
{{ field(class="form-check-input") }}
|
|
32
|
+
{% elif field.type == "FlexibleEnumField" %}
|
|
33
|
+
<input type="text" id="{{ field.id }}" name="{{ field.name }}" value="{{ field.data }}"
|
|
34
|
+
list="{{ field.id }}_options" placeholder="{{ field.render_kw.placeholder if field.render_kw and field.render_kw.placeholder }}"
|
|
35
|
+
class="form-control">
|
|
36
|
+
<datalist id="{{ field.id }}_options">
|
|
37
|
+
{% for key in field.choices %}
|
|
38
|
+
<option value="{{ key }}">{{ key }}</option>
|
|
39
|
+
{% endfor %}
|
|
40
|
+
</datalist>
|
|
41
|
+
{% else %}
|
|
42
|
+
{{ field(class="form-control") }}
|
|
43
|
+
{% endif %}
|
|
30
44
|
</div>
|
|
31
45
|
{% endif %}
|
|
32
46
|
{% endfor %}
|
|
@@ -36,3 +50,4 @@
|
|
|
36
50
|
<button type="submit" class="btn btn-primary">Save</button>
|
|
37
51
|
<button type="button" class="btn btn-primary" id="back">Back</button>
|
|
38
52
|
</form>
|
|
53
|
+
{% endif %}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
{# Tips Button - Fixed Position #}
|
|
2
|
+
<button id="tipsButton" class="btn btn-info tips-button" data-bs-toggle="modal" data-bs-target="#tipsModal" title="View Workflow Tips">
|
|
3
|
+
<i class="bi bi-question-circle"></i>
|
|
4
|
+
</button>
|
|
5
|
+
{# Tips Modal #}
|
|
6
|
+
<div class="modal fade" id="tipsModal" tabindex="-1" aria-labelledby="tipsModalLabel" aria-hidden="true">
|
|
7
|
+
<div class="modal-dialog modal-lg">
|
|
8
|
+
<div class="modal-content">
|
|
9
|
+
<div class="modal-header bg-info text-white">
|
|
10
|
+
<h5 class="modal-title" id="tipsModalLabel">
|
|
11
|
+
<i class="bi bi-lightbulb"></i> Workflow Building Tips
|
|
12
|
+
</h5>
|
|
13
|
+
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
14
|
+
</div>
|
|
15
|
+
<div class="modal-body">
|
|
16
|
+
<div class="accordion" id="tipsAccordion">
|
|
17
|
+
{# Tip 1: Dynamic Variables #}
|
|
18
|
+
<div class="accordion-item">
|
|
19
|
+
<h2 class="accordion-header" id="headingOne">
|
|
20
|
+
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne">
|
|
21
|
+
<i class="bi bi-hash me-2"></i> Dynamic Variables
|
|
22
|
+
</button>
|
|
23
|
+
</h2>
|
|
24
|
+
<div id="collapseOne" class="accordion-collapse collapse show" aria-labelledby="headingOne" data-bs-parent="#tipsAccordion">
|
|
25
|
+
<div class="accordion-body">
|
|
26
|
+
<p><strong>Use <code>#name</code> to make variables dynamic</strong></p>
|
|
27
|
+
<p>When you want a parameter to be adjustable across multiple workflow runs, use <code>#</code> followed by the parameter name in place of the actual value.</p>
|
|
28
|
+
<div class="alert alert-success mb-0">
|
|
29
|
+
<strong>Example:</strong><br>
|
|
30
|
+
Instead of: <code>temperature = 300</code><br>
|
|
31
|
+
Use: <code>temperature = #temperature</code><br>
|
|
32
|
+
<small class="text-muted">This makes "temperature" a dynamic parameter that can be varied in parameter sweeps or optimization runs.</small>
|
|
33
|
+
</div>
|
|
34
|
+
</div>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
{# Tip 2: Repeat vs Dynamic #}
|
|
38
|
+
<div class="accordion-item">
|
|
39
|
+
<h2 class="accordion-header" id="headingTwo">
|
|
40
|
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
|
|
41
|
+
<i class="bi bi-arrow-repeat me-2"></i> Repeat vs Dynamic Parameters
|
|
42
|
+
</button>
|
|
43
|
+
</h2>
|
|
44
|
+
<div id="collapseTwo" class="accordion-collapse collapse" aria-labelledby="headingTwo" data-bs-parent="#tipsAccordion">
|
|
45
|
+
<div class="accordion-body">
|
|
46
|
+
<p><strong>Repeat is for static workflows only</strong></p>
|
|
47
|
+
<ul>
|
|
48
|
+
<li><strong>Static (Repeat):</strong> Runs the exact same workflow multiple times with identical parameters</li>
|
|
49
|
+
<li><strong>Dynamic (#name):</strong> Automatically triggers the <span class="badge bg-primary">Parameter Sweep</span> option, allowing you to vary parameters across runs</li>
|
|
50
|
+
</ul>
|
|
51
|
+
<div class="alert alert-info mb-0">
|
|
52
|
+
<i class="bi bi-info-circle"></i> Use repeat when you want statistical averaging of identical runs. Use dynamic parameters (e.g., <code>#temperature</code>) when you want to explore different parameter values.
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
{# Tip 3: Parameter Sweep #}
|
|
58
|
+
<div class="accordion-item">
|
|
59
|
+
<h2 class="accordion-header" id="headingThree">
|
|
60
|
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseThree" aria-expanded="false" aria-controls="collapseThree">
|
|
61
|
+
<i class="bi bi-sliders me-2"></i> Parameter Sweep Mode
|
|
62
|
+
</button>
|
|
63
|
+
</h2>
|
|
64
|
+
<div id="collapseThree" class="accordion-collapse collapse" aria-labelledby="headingThree" data-bs-parent="#tipsAccordion">
|
|
65
|
+
<div class="accordion-body">
|
|
66
|
+
<p><strong>Automatically enabled when using dynamic parameters</strong></p>
|
|
67
|
+
<p>Parameter sweep allows you to systematically explore different combinations of parameter values.</p>
|
|
68
|
+
<div class="alert alert-warning">
|
|
69
|
+
<strong>Triggered by:</strong> Using <code>#name</code> syntax (e.g., <code>#temperature</code>) in your workflow
|
|
70
|
+
</div>
|
|
71
|
+
<p class="mb-0"><strong>Use cases:</strong> Sensitivity analysis, parameter optimization, design space exploration</p>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
{# Tip 4: Optimizer #}
|
|
76
|
+
<div class="accordion-item">
|
|
77
|
+
<h2 class="accordion-header" id="headingFour">
|
|
78
|
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFour" aria-expanded="false" aria-controls="collapseFour">
|
|
79
|
+
<i class="bi bi-bullseye me-2"></i> Optimizer Mode
|
|
80
|
+
</button>
|
|
81
|
+
</h2>
|
|
82
|
+
<div id="collapseFour" class="accordion-collapse collapse" aria-labelledby="headingFour" data-bs-parent="#tipsAccordion">
|
|
83
|
+
<div class="accordion-body">
|
|
84
|
+
<p><strong>Enabled when you have both dynamic parameters AND output values</strong></p>
|
|
85
|
+
<p>The optimizer automatically finds the best parameter values to optimize your output metric.</p>
|
|
86
|
+
<div class="alert alert-success">
|
|
87
|
+
<strong>Requirements:</strong>
|
|
88
|
+
<ul class="mb-0">
|
|
89
|
+
<li>At least one dynamic parameter using <code>#name</code> syntax (input)</li>
|
|
90
|
+
<li>At least one output value with "Save value as" name (objective function)</li>
|
|
91
|
+
</ul>
|
|
92
|
+
</div>
|
|
93
|
+
<p class="mt-2 mb-0"><small class="text-muted"><i class="bi bi-info-circle"></i> Note: Parameter sweep option remains available even in optimizer mode</small></p>
|
|
94
|
+
</div>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
{# Tip 5: Output Values #}
|
|
98
|
+
<div class="accordion-item">
|
|
99
|
+
<h2 class="accordion-header" id="headingFive">
|
|
100
|
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseFive" aria-expanded="false" aria-controls="collapseFive">
|
|
101
|
+
<i class="bi bi-save me-2"></i> Saving Output Values
|
|
102
|
+
</button>
|
|
103
|
+
</h2>
|
|
104
|
+
<div id="collapseFive" class="accordion-collapse collapse" aria-labelledby="headingFive" data-bs-parent="#tipsAccordion">
|
|
105
|
+
<div class="accordion-body">
|
|
106
|
+
<p><strong>Use "Save value as" to capture important results</strong></p>
|
|
107
|
+
<p>When you want to track or optimize a result from your workflow, give it a meaningful name in the "Save value as" field.</p>
|
|
108
|
+
<div class="alert alert-info">
|
|
109
|
+
<strong>Naming conventions:</strong><br>
|
|
110
|
+
• Use descriptive names: <code>final_stress</code>, <code>total_energy</code>, <code>efficiency</code><br>
|
|
111
|
+
• Use underscores instead of spaces: <code>max_temperature</code> not <code>max temperature</code><br>
|
|
112
|
+
• Keep names concise but clear
|
|
113
|
+
</div>
|
|
114
|
+
<p class="mb-0"><small class="text-muted">Saved values become available for optimization and can be tracked across parameter sweeps.</small></p>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
{# Tip 6: Batch Mode #}
|
|
119
|
+
<div class="accordion-item">
|
|
120
|
+
<h2 class="accordion-header" id="headingSix">
|
|
121
|
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSix" aria-expanded="false" aria-controls="collapseSix">
|
|
122
|
+
<i class="bi bi-collection me-2"></i> Batch Mode Actions
|
|
123
|
+
</button>
|
|
124
|
+
</h2>
|
|
125
|
+
<div id="collapseSix" class="accordion-collapse collapse" aria-labelledby="headingSix" data-bs-parent="#tipsAccordion">
|
|
126
|
+
<div class="accordion-body">
|
|
127
|
+
<p><strong>Mark steps as "Once per batch" to run them only once for multiple samples</strong></p>
|
|
128
|
+
<p>Some actions apply to all samples at once (batch actions), while others must run for each individual sample (per-sample actions).</p>
|
|
129
|
+
<div class="row">
|
|
130
|
+
<div class="col-md-6 mb-3">
|
|
131
|
+
<div class="card h-100">
|
|
132
|
+
<div class="card-header bg-light">
|
|
133
|
+
<strong>Workflow Steps</strong>
|
|
134
|
+
</div>
|
|
135
|
+
<div class="card-body">
|
|
136
|
+
<div class="workflow-left">
|
|
137
|
+
<div class="step-box regular">Add Liquid<br><small>per-sample</small></div>
|
|
138
|
+
<div class="arrow-down">↓</div>
|
|
139
|
+
<div class="step-box regular">Add Solid<br><small>per-sample</small></div>
|
|
140
|
+
<div class="arrow-down">↓</div>
|
|
141
|
+
<div class="step-box batch">Heat Sample<br><small>batch action</small></div>
|
|
142
|
+
<div class="arrow-down">↓</div>
|
|
143
|
+
<div class="step-box regular">Analyze Sample<br><small>per-sample</small></div>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
<div class="col-md-6 mb-3">
|
|
149
|
+
<div class="card h-100">
|
|
150
|
+
<div class="card-header bg-light">
|
|
151
|
+
<strong>Execution (n=3 samples)</strong>
|
|
152
|
+
</div>
|
|
153
|
+
<div class="card-body">
|
|
154
|
+
<div class="workflow-right">
|
|
155
|
+
<div class="sample-group">
|
|
156
|
+
<div class="step-box-small regular">Add Liquid S1</div>
|
|
157
|
+
<div class="step-box-small regular">Add Liquid S2</div>
|
|
158
|
+
<div class="step-box-small regular">Add Liquid S3</div>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="arrow-down">↓</div>
|
|
161
|
+
<div class="sample-group">
|
|
162
|
+
<div class="step-box-small regular">Add Solid S1</div>
|
|
163
|
+
<div class="step-box-small regular">Add Solid S2</div>
|
|
164
|
+
<div class="step-box-small regular">Add Solid S3</div>
|
|
165
|
+
</div>
|
|
166
|
+
<div class="arrow-down">↓</div>
|
|
167
|
+
<div class="step-box batch">Heat All Samples</div>
|
|
168
|
+
<div class="arrow-down">↓</div>
|
|
169
|
+
<div class="sample-group">
|
|
170
|
+
<div class="step-box-small regular">Analyze S1</div>
|
|
171
|
+
<div class="step-box-small regular">Analyze S2</div>
|
|
172
|
+
<div class="step-box-small regular">Analyze S3</div>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
</div>
|
|
178
|
+
</div>
|
|
179
|
+
<div class="alert alert-warning mb-0">
|
|
180
|
+
<strong>Per-sample actions:</strong> Run individually for each sample (Add Liquid, Add Solid, Analyze)<br>
|
|
181
|
+
<strong>Batch actions:</strong> Run once for all samples together (Heat Sample)
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</div>
|
|
186
|
+
{# Tip 7: Best Practices #}
|
|
187
|
+
<div class="accordion-item">
|
|
188
|
+
<h2 class="accordion-header" id="headingSeven">
|
|
189
|
+
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSeven" aria-expanded="false" aria-controls="collapseSeven">
|
|
190
|
+
<i class="bi bi-star me-2"></i> Best Practices
|
|
191
|
+
</button>
|
|
192
|
+
</h2>
|
|
193
|
+
<div id="collapseSeven" class="accordion-collapse collapse" aria-labelledby="headingSeven" data-bs-parent="#tipsAccordion">
|
|
194
|
+
<div class="accordion-body">
|
|
195
|
+
<ul>
|
|
196
|
+
<li><strong>Name parameters clearly:</strong> Use descriptive names like <code>#mesh_size</code> instead of <code>#x</code></li>
|
|
197
|
+
<li><strong>Set reasonable ranges:</strong> Define min/max values that make physical sense for your problem</li>
|
|
198
|
+
<li><strong>Start simple:</strong> Begin with 1-2 parameters before adding more complexity</li>
|
|
199
|
+
<li><strong>Document outputs:</strong> Clearly label which outputs are optimization objectives</li>
|
|
200
|
+
<li><strong>Test first:</strong> Run a single workflow before launching sweeps or optimizations</li>
|
|
201
|
+
<li><strong>Use batch mode wisely:</strong> Mark setup steps as "once per batch" to avoid unnecessary repetition</li>
|
|
202
|
+
</ul>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
</div>
|
|
208
|
+
<div class="modal-footer">
|
|
209
|
+
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
<style>
|
|
214
|
+
/* Tips button styling */
|
|
215
|
+
.tips-button {
|
|
216
|
+
position: fixed;
|
|
217
|
+
bottom: 30px;
|
|
218
|
+
right: 30px;
|
|
219
|
+
width: 60px;
|
|
220
|
+
height: 60px;
|
|
221
|
+
border-radius: 50%;
|
|
222
|
+
font-size: 24px;
|
|
223
|
+
box-shadow: 0 4px 12px rgba(0,0,0,0.15);
|
|
224
|
+
z-index: 1000;
|
|
225
|
+
display: flex;
|
|
226
|
+
align-items: center;
|
|
227
|
+
justify-content: center;
|
|
228
|
+
transition: all 0.3s ease;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.tips-button:hover {
|
|
232
|
+
transform: scale(1.1);
|
|
233
|
+
box-shadow: 0 6px 20px rgba(0,0,0,0.2);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
.tips-button i {
|
|
237
|
+
line-height: 1;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
.accordion-body code {
|
|
242
|
+
background-color: #f8f9fa;
|
|
243
|
+
padding: 2px 6px;
|
|
244
|
+
border-radius: 3px;
|
|
245
|
+
color: #d63384;
|
|
246
|
+
}
|
|
247
|
+
/* Batch mode visual styling */
|
|
248
|
+
.workflow-left {
|
|
249
|
+
display: flex;
|
|
250
|
+
flex-direction: column;
|
|
251
|
+
align-items: center;
|
|
252
|
+
gap: 10px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.workflow-right {
|
|
256
|
+
display: flex;
|
|
257
|
+
flex-direction: column;
|
|
258
|
+
align-items: center;
|
|
259
|
+
gap: 10px;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.sample-group {
|
|
263
|
+
display: flex;
|
|
264
|
+
gap: 8px;
|
|
265
|
+
padding: 10px;
|
|
266
|
+
background: #f8f9fa;
|
|
267
|
+
border-radius: 6px;
|
|
268
|
+
border: 1px dashed #dee2e6;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.step-box {
|
|
272
|
+
padding: 12px 20px;
|
|
273
|
+
border-radius: 6px;
|
|
274
|
+
font-size: 0.85em;
|
|
275
|
+
text-align: center;
|
|
276
|
+
min-width: 120px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.step-box.regular {
|
|
280
|
+
background: white;
|
|
281
|
+
border: 2px solid #dee2e6;
|
|
282
|
+
color: #495057;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.step-box.batch {
|
|
286
|
+
background: #e7f3ff;
|
|
287
|
+
border: 2px solid #0d6efd;
|
|
288
|
+
color: #0d6efd;
|
|
289
|
+
font-weight: 600;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.step-box-small {
|
|
293
|
+
padding: 8px 12px;
|
|
294
|
+
border-radius: 4px;
|
|
295
|
+
font-size: 0.75em;
|
|
296
|
+
text-align: center;
|
|
297
|
+
background: white;
|
|
298
|
+
border: 1px solid #dee2e6;
|
|
299
|
+
color: #495057;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
.step-box-small.regular {
|
|
303
|
+
background: white;
|
|
304
|
+
border: 1px solid #dee2e6;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.arrow-down {
|
|
308
|
+
font-size: 1.5em;
|
|
309
|
+
color: #6c757d;
|
|
310
|
+
line-height: 1;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
.arrow {
|
|
314
|
+
font-size: 1.2em;
|
|
315
|
+
color: #6c757d;
|
|
316
|
+
}
|
|
317
|
+
</style>
|
|
318
|
+
</div>
|
|
@@ -39,7 +39,29 @@
|
|
|
39
39
|
</ul>
|
|
40
40
|
</div>
|
|
41
41
|
</div>
|
|
42
|
-
|
|
42
|
+
{% if block_variables %}
|
|
43
|
+
<div class="accordion-item design-control">
|
|
44
|
+
<h5 class="accordion-header">
|
|
45
|
+
<button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#block" role="button" aria-expanded="false" aria-controls="collapseExample">
|
|
46
|
+
Methods
|
|
47
|
+
</button>
|
|
48
|
+
</h5>
|
|
49
|
+
<div class="accordion-collapse collapse show" id="block">
|
|
50
|
+
<ul class="list-group">
|
|
51
|
+
{% for category in block_variables %}
|
|
52
|
+
<button class="list-group-item list-group-item-action"
|
|
53
|
+
type="button"
|
|
54
|
+
name="device"
|
|
55
|
+
value="{{category}}"
|
|
56
|
+
data-get-url="{{ url_for('design.get_operation_sidebar', instrument=category) }}"
|
|
57
|
+
onclick="updateInstrumentPanel(this)">
|
|
58
|
+
{{ category|format_name }}
|
|
59
|
+
</button>
|
|
60
|
+
{% endfor%}
|
|
61
|
+
</ul>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
{% endif %}
|
|
43
65
|
{% if local_variables %}
|
|
44
66
|
<div class="accordion-item design-control">
|
|
45
67
|
<h5 class="accordion-header">
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
{# Python code overlay component #}
|
|
2
|
-
{#{% if session.get('show_code') %}#}
|
|
1
|
+
{# Python code overlay component - Pure HTML #}
|
|
3
2
|
<style>
|
|
4
3
|
.code-overlay {
|
|
5
4
|
position: fixed;
|
|
@@ -16,7 +15,7 @@
|
|
|
16
15
|
transform: translateX(0);
|
|
17
16
|
}
|
|
18
17
|
</style>
|
|
19
|
-
|
|
18
|
+
|
|
20
19
|
{% if session.get('show_code') %}
|
|
21
20
|
<div id="pythonCodeOverlay" class="code-overlay bg-light border-start show">
|
|
22
21
|
{% else %}
|
|
@@ -29,11 +28,29 @@
|
|
|
29
28
|
</button>
|
|
30
29
|
</div>
|
|
31
30
|
<div class="overlay-content p-3">
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
31
|
+
<!-- Top toggles (Single / Batch) -->
|
|
32
|
+
<div class="btn-group mb-3">
|
|
33
|
+
<button type="button" class="btn btn-outline-primary mode-toggle active" data-mode="single">Single</button>
|
|
34
|
+
<button type="button" class="btn btn-outline-primary mode-toggle" data-mode="batch">Batch</button>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
{# <!-- Secondary toggles (By Sample / By Step) TODO -->#}
|
|
38
|
+
{# <div class="btn-group mb-3" id="batch-options" style="display: none;">#}
|
|
39
|
+
{# <button type="button" class="btn btn-outline-secondary batch-toggle active" data-batch="sample">By Sample</button>#}
|
|
40
|
+
{# <button type="button" class="btn btn-outline-secondary batch-toggle" data-batch="step">By Step</button>#}
|
|
41
|
+
{# </div>#}
|
|
42
|
+
|
|
43
|
+
<!-- Code display -->
|
|
44
|
+
<pre><code id="python-code" class="language-python">Loading...</code></pre>
|
|
45
|
+
|
|
46
|
+
<!-- Action buttons -->
|
|
47
|
+
<div class="mt-2">
|
|
48
|
+
<button type="button" id="copy-code" class="btn btn-sm btn-outline-success">
|
|
49
|
+
<i class="bi bi-clipboard"></i> Copy
|
|
50
|
+
</button>
|
|
51
|
+
<button type="button" id="download-code" class="btn btn-sm btn-outline-primary">
|
|
52
|
+
<i class="bi bi-download"></i> Download
|
|
53
|
+
</button>
|
|
54
|
+
</div>
|
|
38
55
|
</div>
|
|
39
|
-
</div>
|
|
56
|
+
</div>
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
|
|
24
24
|
{# Include all modals #}
|
|
25
25
|
{% include 'components/modals.html' %}
|
|
26
|
+
{% include 'components/info_modal.html' %}
|
|
27
|
+
|
|
26
28
|
|
|
27
29
|
{# Include all scripts #}
|
|
28
30
|
<script>
|
|
@@ -32,6 +34,7 @@
|
|
|
32
34
|
const scriptStepUrl = `{{ url_for('design.design_steps.get_step', uuid=0) }}`;
|
|
33
35
|
const scriptStepDupUrl = `{{ url_for('design.design_steps.duplicate_action', uuid=0) }}`;
|
|
34
36
|
const scriptDeleteUrl = "{{ url_for('design.clear_draft') }}";
|
|
37
|
+
const scriptCompileUrl = "{{ url_for('design.compile_preview') }}";
|
|
35
38
|
</script>
|
|
36
39
|
<script src="{{ url_for('static', filename='js/sortable_design.js') }}"></script>
|
|
37
40
|
<script src="{{ url_for('static', filename='js/action_handlers.js') }}"></script>
|