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,4 +1,5 @@
1
1
  {# Bayesian optimization tab component #}
2
+
2
3
  <div class="tab-pane fade" id="tab3" role="tabpanel" aria-labelledby="tab3-tab">
3
4
 
4
5
 
@@ -12,136 +13,387 @@
12
13
  {# </div>#}
13
14
  <h6 class="fw-bold mt-2 mb-1">Load Previous Data</h6>
14
15
 
15
- <form method="POST" name="bo" action="{{ url_for('execute.experiment_run') }}">
16
- <div class="container py-2">
17
- <!-- Data Loading Section -->
18
- <div class="input-group">
19
- <label class="input-group-text"><i class="bi bi-folder2-open"></i></label>
20
- <select class="form-select" id="existing_data" name="existing_data">
21
- <option value="">Load existing data...</option>
22
- {% for data in data_list %}
23
- <option value="{{ data }}">{{ data }} </option>
24
- {% endfor %}
25
- </select>
26
- </div>
27
- <!-- Custom path input -->
28
- <div class="row align-items-center mb-3" id="custom_path_row" style="display: none;">
29
- <div class="col-3 col-form-label-sm">
30
- Custom Path:
31
- </div>
32
- <div class="col-7">
33
- <input type="text" class="form-control form-control-sm" id="custom_path" name="custom_path" placeholder="/path/to/data/folder">
16
+ <form method="POST" name="bo" action="{{ url_for('execute.run_bo') }}">
17
+ <div class="container py-2">
18
+ <!-- Optimizer Selection -->
19
+ <div class="input-group mb-3">
20
+ <label class="input-group-text"><i class="bi bi-gear"></i></label>
21
+ <select class="form-select" id="optimizer_type" name="optimizer_type" onchange="updateOptimizerInfo()">
22
+ {# <option value="">Select optimizer...</option>#}
23
+ {% for optimizer_name, optimizer_info in optimizer_schema.items() %}
24
+ <option value="{{ optimizer_name }}"
25
+ data-multiobjective="{{ optimizer_info.multiple_objectives }}"
26
+ data-parameter-types="{{ optimizer_info.parameter_types|join(',') }}"
27
+ data-optimizer-config="{{ optimizer_info.optimizer_config|tojson|e }}">
28
+ {{ optimizer_name }} {% if optimizer_info.multiple_objectives %}(Multi-objective supported){% endif %}
29
+ </option>
30
+ {% endfor %}
31
+ </select>
34
32
  </div>
35
- <div class="col-2">
36
- <button type="button" class="btn btn-sm btn-outline-secondary" onclick="validateCustomPath()">Validate</button>
33
+
34
+ <!-- Data Loading Section -->
35
+ <div class="input-group mb-3">
36
+ <label class="input-group-text"><i class="bi bi-folder2-open"></i></label>
37
+ <select class="form-select" id="existing_data" name="existing_data">
38
+ <option value="">Load existing data...</option>
39
+ {% for data in data_list %}
40
+ <option value="{{ data }}">{{ data }} </option>
41
+ {% endfor %}
42
+ </select>
37
43
  </div>
38
- </div>
39
44
 
40
- <!-- Data preview section -->
41
- <div class="row mb-3" id="data_preview_section" style="display: none;">
42
- <div class="col-12">
43
- <div class="card">
44
- <div class="card-header py-2">
45
- <small class="fw-bold">Data Preview</small>
46
- </div>
47
- <div class="card-body py-2">
48
- <div id="data_preview_content">
49
- <small class="text-muted">Select a data source to preview</small>
45
+ <!-- Data preview section -->
46
+ <div class="row mb-3" id="data_preview_section" style="display: none;">
47
+ <div class="col-12">
48
+ <div class="card">
49
+ <div class="card-header py-2">
50
+ <small class="fw-bold">Data Preview</small>
51
+ </div>
52
+ <div class="card-body py-2">
53
+ <div id="data_preview_content">
54
+ <small class="text-muted">Select a data source to preview</small>
55
+ </div>
50
56
  </div>
51
57
  </div>
52
58
  </div>
53
59
  </div>
54
- </div>
55
60
 
56
- <hr class="my-3">
61
+ <hr class="my-3">
57
62
 
58
- <!-- Parameters -->
59
- <h6 class="fw-bold mt-2 mb-1">Parameters</h6>
60
- {% for config in config_list %}
61
- <div class="row align-items-center mb-2">
62
- <div class="col-3 col-form-label-sm">
63
- {{ config }}:
64
- </div>
65
- <div class="col-6">
66
- <select class="form-select form-select-sm" id="{{config}}_type" name="{{config}}_type">
67
- <option selected value="range">range</option>
68
- <option value="choice">choice</option>
69
- <option value="fixed">fixed</option>
70
- </select>
63
+ <!-- Tabs Navigation -->
64
+ <ul class="nav nav-tabs" id="configTabs" role="tablist">
65
+ <li class="nav-item" role="presentation">
66
+ <button class="nav-link active" id="parameters-tab" data-bs-toggle="tab" data-bs-target="#parameters" type="button" role="tab" aria-controls="parameters" aria-selected="true">
67
+ Parameters
68
+ </button>
69
+ </li>
70
+ <li class="nav-item" role="presentation">
71
+ <button class="nav-link" id="advanced-tab" data-bs-toggle="tab" data-bs-target="#advanced" type="button" role="tab" aria-controls="advanced" aria-selected="false">
72
+ Advanced Settings
73
+ </button>
74
+ </li>
75
+ </ul>
76
+
77
+ <!-- Tab Content -->
78
+ <div class="tab-content" id="configTabContent">
79
+ <!-- Parameters Tab -->
80
+ <div class="tab-pane fade show active" id="parameters" role="tabpanel" aria-labelledby="parameters-tab">
81
+ <div class="py-3">
82
+ <h6 class="fw-bold mt-2 mb-1">Parameters</h6>
83
+ <div id="parameters_container">
84
+ {% for config in config_list %}
85
+ <div class="row align-items-center mb-2 parameter-row">
86
+ <div class="col-3 col-form-label-sm">
87
+ {{ config }}:
88
+ </div>
89
+ <div class="col-3">
90
+ <select class="form-select form-select-sm parameter-type" id="{{config}}_type" name="{{config}}_type" onchange="updateParameterInputs(this)">
91
+ <!-- Options will be populated by JavaScript -->
92
+ </select>
93
+ </div>
94
+ <div class="col-6 parameter-inputs">
95
+ <input type="text" class="form-control form-control-sm single-input" id="{{config}}_value" name="{{config}}_value" placeholder="1, 2, 3">
96
+ <div class="range-inputs" style="display: none;">
97
+ <div class="row">
98
+ <div class="col-6">
99
+ <input type="text" class="form-control form-control-sm" id="{{config}}_min" name="{{config}}_min" placeholder="Min value">
100
+ </div>
101
+ <div class="col-6">
102
+ <input type="text" class="form-control form-control-sm" id="{{config}}_max" name="{{config}}_max" placeholder="Max value">
103
+ </div>
104
+ </div>
105
+ </div>
106
+ </div>
107
+ </div>
108
+ {% endfor %}
109
+ </div>
110
+
111
+ <!-- Objectives -->
112
+ <h6 class="fw-bold mt-3 mb-1">Objectives</h6>
113
+ {% for objective in return_list %}
114
+ <div class="row align-items-center mb-2">
115
+ <div class="col-3 col-form-label-sm">
116
+ {{ objective }}:
117
+ </div>
118
+ <div class="col-6">
119
+ <select class="form-select form-select-sm" id="{{objective}}_min" name="{{objective}}_min">
120
+ <option selected>minimize</option>
121
+ <option>maximize</option>
122
+ <option>none</option>
123
+ </select>
124
+ </div>
125
+ {% if not return_list|length == 1 %}
126
+ <div class="col-3">
127
+ <input class="form-control" type="number" id="{{objective}}_weight" name="{{objective}}_weight" min="1" max="1000" value="1">
128
+ </div>
129
+ {% endif %}
130
+ </div>
131
+ {% endfor %}
132
+
133
+ <!-- Budget -->
134
+ <h6 class="fw-bold mt-3 mb-1">Budget</h6>
135
+ <div class="input-group mb-3">
136
+ <label class="input-group-text" for="repeat">Max iteration </label>
137
+ <input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="25">
138
+ </div>
139
+ </div>
71
140
  </div>
72
- <div class="col-3">
73
- <input type="text" class="form-control form-control-sm" id="{{config}}_value" name="{{config}}_value" placeholder="1, 2, 3">
141
+
142
+ <!-- Advanced Settings Tab -->
143
+ <div class="tab-pane fade" id="advanced" role="tabpanel" aria-labelledby="advanced-tab">
144
+ <div class="py-3">
145
+ <h6 class="fw-bold mt-2 mb-1">Optimizer Configuration</h6>
146
+ <div id="optimizer_config_container" style="display: none;">
147
+
148
+ <!-- Step 1 Configuration -->
149
+ <div class="card mb-3">
150
+ <div class="card-header py-2">
151
+ <small class="fw-bold">Step 1 Configuration</small>
152
+ </div>
153
+ <div class="card-body py-2">
154
+ <div class="row align-items-center mb-2">
155
+ <div class="col-3 col-form-label-sm">
156
+ Model:
157
+ </div>
158
+ <div class="col-6">
159
+ <select class="form-select form-select-sm" id="step1_model" name="step1_model">
160
+ <!-- Options will be populated by JavaScript -->
161
+ </select>
162
+ </div>
163
+ </div>
164
+ <div class="row align-items-center mb-2" id="step1_num_samples_row">
165
+ <div class="col-3 col-form-label-sm">
166
+ Num Samples:
167
+ </div>
168
+ <div class="col-6">
169
+ <input type="number" class="form-control form-control-sm" id="step1_num_samples" name="step1_num_samples" min="1" value="">
170
+ </div>
171
+ </div>
172
+ </div>
173
+ </div>
174
+
175
+ <!-- Step 2 Configuration -->
176
+ <div class="card mb-3">
177
+ <div class="card-header py-2">
178
+ <small class="fw-bold">Step 2 Configuration</small>
179
+ </div>
180
+ <div class="card-body py-2">
181
+ <div class="row align-items-center mb-2">
182
+ <div class="col-3 col-form-label-sm">
183
+ Model:
184
+ </div>
185
+ <div class="col-6">
186
+ <select class="form-select form-select-sm" id="step2_model" name="step2_model">
187
+ <!-- Options will be populated by JavaScript -->
188
+ </select>
189
+ </div>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ </div>
194
+ <div id="optimizer_config_placeholder">
195
+ <small class="text-muted">Select an optimizer to configure advanced settings</small>
196
+ </div>
197
+ </div>
74
198
  </div>
75
199
  </div>
76
- {% endfor %}
77
- <!-- Objective -->
78
- <h6 class="fw-bold mt-3 mb-1">Objectives</h6>
79
- {% for objective in return_list %}
80
- <div class="row align-items-center mb-2">
81
- <div class="col-3 col-form-label-sm">
82
- {{ objective }}:
83
- </div>
84
- <div class="col-6">
85
- <select class="form-select form-select-sm" id="{{objective}}_min" name="{{objective}}_min">
86
- <option selected>minimize</option>
87
- <option>maximize</option>
88
- <option>none</option>
89
- </select>
200
+
201
+ {% if not no_deck_warning%}
202
+ <div class="input-group mb-3 mt-3">
203
+ <button class="form-control" type="submit" name="bo">Run</button>
90
204
  </div>
91
- </div>
92
- {% endfor %}
93
- <h6 class="fw-bold mt-3 mb-1">Budget</h6>
94
- <div class="input-group mb-3">
95
- <label class="input-group-text" for="repeat">Max iteration </label>
96
- <input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="25">
205
+ {% endif %}
97
206
  </div>
98
- {% if not no_deck_warning%}
99
- <div class="input-group mb-3">
100
- <button class="form-control" type="submit" name="bo">Run</button>
101
- </div>
102
- {% endif %}
103
- </div>
104
- </form>
207
+ </form>
105
208
  </div>
106
- <script>
107
- document.addEventListener('DOMContentLoaded', function() {
108
- const dataSelect = document.getElementById('existing_data');
109
- const previewSection = document.getElementById('data_preview_section');
110
- const previewContent = document.getElementById('data_preview_content');
111
-
112
- dataSelect.addEventListener('change', function() {
113
- const filename = dataSelect.value;
114
- if (!filename) {
115
- previewSection.style.display = 'none';
116
- previewContent.innerHTML = '<small class="text-muted">Select a data source to preview</small>';
209
+ <script>
210
+
211
+ const optimizerSchema = {{ optimizer_schema|tojson }};
212
+
213
+ document.addEventListener('DOMContentLoaded', function() {
214
+ const dataSelect = document.getElementById('existing_data');
215
+ const previewSection = document.getElementById('data_preview_section');
216
+ const previewContent = document.getElementById('data_preview_content');
217
+
218
+ // Data preview functionality
219
+ dataSelect.addEventListener('change', function() {
220
+ const filename = dataSelect.value;
221
+ if (!filename) {
222
+ previewSection.style.display = 'none';
223
+ previewContent.innerHTML = '<small class="text-muted">Select a data source to preview</small>';
224
+ return;
225
+ }
226
+ fetch('{{ url_for("execute.data_preview", filename="FILENAME") }}'.replace('FILENAME', encodeURIComponent(filename)))
227
+ .then(response => {
228
+ if (!response.ok) throw new Error('Network response was not ok');
229
+ return response.json();
230
+ })
231
+ .then(data => {
232
+ previewSection.style.display = '';
233
+ if (!data.rows || data.rows.length === 0) {
234
+ previewContent.innerHTML = '<small class="text-muted">No data found in file.</small>';
235
+ return;
236
+ }
237
+ let html = '<table class="table table-sm table-bordered mb-0"><thead><tr>';
238
+ data.columns.forEach(col => html += `<th>${col}</th>`);
239
+ html += '</tr></thead><tbody>';
240
+ data.rows.forEach(row => {
241
+ html += '<tr>';
242
+ data.columns.forEach(col => html += `<td>${row[col] || ''}</td>`);
243
+ html += '</tr>';
244
+ });
245
+ html += '</tbody></table>';
246
+ previewContent.innerHTML = html;
247
+ })
248
+ .catch(() => {
249
+ previewSection.style.display = '';
250
+ previewContent.innerHTML = '<small class="text-danger">Failed to load preview.</small>';
251
+ });
252
+ });
253
+ });
254
+
255
+ function updateOptimizerInfo() {
256
+ const optimizerSelect = document.getElementById('optimizer_type');
257
+ const selectedOption = optimizerSelect.selectedOptions[0];
258
+
259
+ if (!selectedOption || !selectedOption.value) {
260
+ // Hide optimizer config and reset parameter types
261
+ document.getElementById('optimizer_config_container').style.display = 'none';
262
+ document.getElementById('optimizer_config_placeholder').style.display = 'block';
263
+ resetParameterTypes();
117
264
  return;
118
265
  }
119
- fetch('{{ url_for("execute.data_preview", filename="FILENAME") }}'.replace('FILENAME', encodeURIComponent(filename)))
120
- .then(response => {
121
- if (!response.ok) throw new Error('Network response was not ok');
122
- return response.json();
123
- })
124
- .then(data => {
125
- previewSection.style.display = '';
126
- if (!data.rows || data.rows.length === 0) {
127
- previewContent.innerHTML = '<small class="text-muted">No data found in file.</small>';
128
- return;
266
+
267
+ // Update parameter types
268
+ const parameterTypes = selectedOption.dataset.parameterTypes.split(',');
269
+ updateParameterTypeOptions(parameterTypes);
270
+
271
+ // Update optimizer config - use the stored schema data instead
272
+ const optimizerName = selectedOption.value;
273
+ if (optimizerSchema[optimizerName] && optimizerSchema[optimizerName].optimizer_config) {
274
+ updateOptimizerConfig(optimizerSchema[optimizerName].optimizer_config);
275
+ } else {
276
+ document.getElementById('optimizer_config_container').style.display = 'none';
277
+ document.getElementById('optimizer_config_placeholder').style.display = 'block';
278
+ }
279
+ }
280
+
281
+ function updateParameterTypeOptions(availableTypes) {
282
+ const parameterTypeSelects = document.querySelectorAll('.parameter-type');
283
+
284
+ parameterTypeSelects.forEach(select => {
285
+ // Clear existing options
286
+ select.innerHTML = '';
287
+
288
+ // Add available options based on optimizer
289
+ availableTypes.forEach(type => {
290
+ const option = document.createElement('option');
291
+ option.value = type;
292
+ option.textContent = type;
293
+ if (type === 'range') {
294
+ option.selected = true;
129
295
  }
130
- let html = '<table class="table table-sm table-bordered mb-0"><thead><tr>';
131
- data.columns.forEach(col => html += `<th>${col}</th>`);
132
- html += '</tr></thead><tbody>';
133
- data.rows.forEach(row => {
134
- html += '<tr>';
135
- data.columns.forEach(col => html += `<td>${row[col] || ''}</td>`);
136
- html += '</tr>';
137
- });
138
- html += '</tbody></table>';
139
- previewContent.innerHTML = html;
140
- })
141
- .catch(() => {
142
- previewSection.style.display = '';
143
- previewContent.innerHTML = '<small class="text-danger">Failed to load preview.</small>';
296
+ select.appendChild(option);
144
297
  });
298
+
299
+ // Update inputs for the current selection
300
+ updateParameterInputs(select);
301
+ });
302
+ }
303
+
304
+ function resetParameterTypes() {
305
+ const parameterTypeSelects = document.querySelectorAll('.parameter-type');
306
+
307
+ parameterTypeSelects.forEach(select => {
308
+ select.innerHTML = '';
309
+ const defaultTypes = ['range', 'choice', 'fixed'];
310
+ defaultTypes.forEach(type => {
311
+ const option = document.createElement('option');
312
+ option.value = type;
313
+ option.textContent = type;
314
+ if (type === 'range') {
315
+ option.selected = true;
316
+ }
317
+ select.appendChild(option);
318
+ });
319
+
320
+ updateParameterInputs(select);
321
+ });
322
+ }
323
+
324
+ function updateParameterInputs(selectElement) {
325
+ const parameterRow = selectElement.closest('.parameter-row');
326
+ const singleInput = parameterRow.querySelector('.single-input');
327
+ const rangeInputs = parameterRow.querySelector('.range-inputs');
328
+
329
+ if (selectElement.value === 'range') {
330
+ singleInput.style.display = 'none';
331
+ rangeInputs.style.display = 'block';
332
+ } else {
333
+ singleInput.style.display = 'block';
334
+ rangeInputs.style.display = 'none';
335
+ }
336
+ }
337
+
338
+ function updateOptimizerConfig(config) {
339
+ const container = document.getElementById('optimizer_config_container');
340
+ const placeholder = document.getElementById('optimizer_config_placeholder');
341
+
342
+ console.log('Updating optimizer config:', config); // Debug log
343
+
344
+ if (!config || !config.step_1) {
345
+ container.style.display = 'none';
346
+ placeholder.style.display = 'block';
347
+ return;
348
+ }
349
+
350
+ placeholder.style.display = 'none';
351
+ container.style.display = 'block';
352
+
353
+ // Update Step 1
354
+ const step1ModelSelect = document.getElementById('step1_model');
355
+ if (step1ModelSelect && config.step_1.model) {
356
+ step1ModelSelect.innerHTML = '';
357
+ config.step_1.model.forEach(model => {
358
+ const option = document.createElement('option');
359
+ option.value = model;
360
+ option.textContent = model;
361
+ step1ModelSelect.appendChild(option);
362
+ });
363
+ }
364
+
365
+ // Update Step 1 num_samples if exists
366
+ const step1NumSamplesRow = document.getElementById('step1_num_samples_row');
367
+ const step1NumSamplesInput = document.getElementById('step1_num_samples');
368
+ if (step1NumSamplesRow && step1NumSamplesInput) {
369
+ if (config.step_1.num_samples !== undefined) {
370
+ step1NumSamplesRow.style.display = '';
371
+ step1NumSamplesInput.value = config.step_1.num_samples;
372
+ } else {
373
+ step1NumSamplesRow.style.display = 'none';
374
+ }
375
+ }
376
+
377
+ // Update Step 2
378
+ if (config.step_2) {
379
+ const step2ModelSelect = document.getElementById('step2_model');
380
+ if (step2ModelSelect && config.step_2.model) {
381
+ step2ModelSelect.innerHTML = '';
382
+ config.step_2.model.forEach(model => {
383
+ const option = document.createElement('option');
384
+ option.value = model;
385
+ option.textContent = model;
386
+ step2ModelSelect.appendChild(option);
387
+ });
388
+ }
389
+ }
390
+ }
391
+
392
+ // Initialize parameter inputs on page load
393
+ document.addEventListener('DOMContentLoaded', function() {
394
+ const parameterTypeSelects = document.querySelectorAll('.parameter-type');
395
+ parameterTypeSelects.forEach(select => {
396
+ updateParameterInputs(select);
397
+ });
145
398
  });
146
- });
147
- </script>
399
+ </script>
@@ -5,7 +5,7 @@
5
5
  <div class="card-header d-flex justify-content-between align-items-center">
6
6
  <h6 class="mb-0"><i class="bi bi-file-earmark-text"></i> Configuration File</h6>
7
7
  <small class="text-muted">
8
- <a href="{{ url_for('design.design_files.download', filetype='configure') }}">
8
+ <a href="{{ url_for('execute.execute_files.download_empty_config', filetype='configure') }}">
9
9
  <i class="bi bi-download"></i> Download Empty Template
10
10
  </a>
11
11
  </small>