ivoryos 1.0.9__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.
- ivoryos/__init__.py +26 -7
- ivoryos/routes/api/api.py +56 -0
- ivoryos/routes/auth/auth.py +5 -5
- ivoryos/routes/control/control.py +77 -372
- ivoryos/routes/control/control_file.py +36 -0
- ivoryos/routes/control/control_new_device.py +142 -0
- ivoryos/routes/control/templates/controllers.html +166 -0
- ivoryos/routes/control/templates/controllers_new.html +112 -0
- ivoryos/routes/control/utils.py +38 -0
- ivoryos/routes/data/data.py +129 -0
- ivoryos/routes/data/templates/components/step_card.html +13 -0
- ivoryos/routes/{database/templates/database → data/templates}/workflow_database.html +14 -8
- ivoryos/routes/{database/templates/database → data/templates}/workflow_view.html +3 -3
- ivoryos/routes/design/__init__.py +4 -0
- ivoryos/routes/design/design.py +298 -656
- ivoryos/routes/design/design_file.py +68 -0
- ivoryos/routes/design/design_step.py +145 -0
- ivoryos/routes/design/templates/components/action_form.html +53 -0
- ivoryos/routes/design/templates/components/actions_panel.html +25 -0
- ivoryos/routes/design/templates/components/autofill_toggle.html +10 -0
- ivoryos/routes/design/templates/components/canvas.html +5 -0
- ivoryos/routes/design/templates/components/canvas_footer.html +9 -0
- ivoryos/routes/design/templates/components/canvas_header.html +75 -0
- ivoryos/routes/design/templates/components/canvas_main.html +34 -0
- ivoryos/routes/design/templates/components/deck_selector.html +10 -0
- ivoryos/routes/design/templates/components/edit_action_form.html +38 -0
- ivoryos/routes/design/templates/components/instruments_panel.html +66 -0
- ivoryos/routes/design/templates/components/modals/drop_modal.html +17 -0
- ivoryos/routes/design/templates/components/modals/json_modal.html +22 -0
- ivoryos/routes/design/templates/components/modals/new_script_modal.html +17 -0
- ivoryos/routes/design/templates/components/modals/rename_modal.html +23 -0
- ivoryos/routes/design/templates/components/modals/saveas_modal.html +27 -0
- ivoryos/routes/design/templates/components/modals.html +6 -0
- ivoryos/routes/design/templates/components/python_code_overlay.html +39 -0
- ivoryos/routes/design/templates/components/sidebar.html +15 -0
- ivoryos/routes/design/templates/components/text_to_code_panel.html +20 -0
- ivoryos/routes/design/templates/experiment_builder.html +41 -0
- ivoryos/routes/execute/__init__.py +0 -0
- ivoryos/routes/execute/execute.py +317 -0
- ivoryos/routes/execute/execute_file.py +78 -0
- ivoryos/routes/execute/templates/components/error_modal.html +20 -0
- ivoryos/routes/execute/templates/components/logging_panel.html +31 -0
- ivoryos/routes/execute/templates/components/progress_panel.html +27 -0
- ivoryos/routes/execute/templates/components/run_panel.html +9 -0
- ivoryos/routes/execute/templates/components/run_tabs.html +17 -0
- ivoryos/routes/execute/templates/components/tab_bayesian.html +399 -0
- ivoryos/routes/execute/templates/components/tab_configuration.html +98 -0
- ivoryos/routes/execute/templates/components/tab_repeat.html +14 -0
- ivoryos/routes/execute/templates/experiment_run.html +294 -0
- ivoryos/routes/library/__init__.py +0 -0
- ivoryos/routes/library/library.py +159 -0
- ivoryos/routes/{database/templates/database/scripts_database.html → library/templates/library.html} +30 -22
- ivoryos/routes/main/main.py +1 -1
- ivoryos/routes/main/templates/{main/home.html → home.html} +4 -4
- ivoryos/socket_handlers.py +52 -0
- ivoryos/static/js/action_handlers.js +213 -0
- ivoryos/static/js/db_delete.js +23 -0
- ivoryos/static/js/script_metadata.js +39 -0
- ivoryos/static/js/sortable_design.js +89 -56
- ivoryos/static/js/ui_state.js +113 -0
- ivoryos/templates/base.html +4 -4
- ivoryos/utils/bo_campaign.py +179 -3
- ivoryos/utils/db_models.py +14 -5
- ivoryos/utils/form.py +5 -9
- ivoryos/utils/global_config.py +13 -1
- ivoryos/utils/py_to_json.py +225 -0
- ivoryos/utils/script_runner.py +49 -7
- ivoryos/utils/serilize.py +203 -0
- ivoryos/utils/task_runner.py +4 -1
- ivoryos/version.py +1 -1
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0b1.dist-info}/METADATA +5 -8
- ivoryos-1.2.0b1.dist-info/RECORD +105 -0
- ivoryos/routes/control/templates/control/controllers.html +0 -78
- ivoryos/routes/control/templates/control/controllers_home.html +0 -55
- ivoryos/routes/control/templates/control/controllers_new.html +0 -89
- ivoryos/routes/database/database.py +0 -306
- ivoryos/routes/database/templates/database/step_card.html +0 -7
- ivoryos/routes/design/templates/design/experiment_builder.html +0 -521
- ivoryos/routes/design/templates/design/experiment_run.html +0 -558
- ivoryos-1.0.9.dist-info/RECORD +0 -61
- /ivoryos/routes/auth/templates/{auth/login.html → login.html} +0 -0
- /ivoryos/routes/auth/templates/{auth/signup.html → signup.html} +0 -0
- /ivoryos/routes/{database → data}/__init__.py +0 -0
- /ivoryos/routes/main/templates/{main/help.html → help.html} +0 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0b1.dist-info}/LICENSE +0 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0b1.dist-info}/WHEEL +0 -0
- {ivoryos-1.0.9.dist-info → ivoryos-1.2.0b1.dist-info}/top_level.txt +0 -0
|
@@ -1,558 +0,0 @@
|
|
|
1
|
-
{% extends 'base.html' %}
|
|
2
|
-
{% block title %}IvoryOS | Design execution{% endblock %}
|
|
3
|
-
|
|
4
|
-
{% block body %}
|
|
5
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.4.1/socket.io.js"></script>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
{% if no_deck_warning and not dismiss %}
|
|
9
|
-
{# auto pop import when there is no deck#}
|
|
10
|
-
<script type="text/javascript">
|
|
11
|
-
function OpenBootstrapPopup() {
|
|
12
|
-
$("#importModal").modal('show');
|
|
13
|
-
}
|
|
14
|
-
window.onload = function () {
|
|
15
|
-
OpenBootstrapPopup();
|
|
16
|
-
};
|
|
17
|
-
</script>
|
|
18
|
-
{% endif %}
|
|
19
|
-
|
|
20
|
-
<div class="row">
|
|
21
|
-
{% if script['script'] or script['prep'] or script['cleanup'] %}
|
|
22
|
-
<div class="col-lg-6 col-sm-12" id="run-panel" style="{{ 'display: none;' if pause_status else '' }}">
|
|
23
|
-
<ul class="nav nav-tabs" id="myTabs" role="tablist">
|
|
24
|
-
<li class="nav-item" role="presentation">
|
|
25
|
-
<a class="nav-link {{ 'disabled' if config_list else '' }} {{ 'active' if not config_list else '' }}" id="tab1-tab" data-bs-toggle="tab" href="#tab1" role="tab" aria-controls="tab1" aria-selected="false">Repeat</a>
|
|
26
|
-
</li>
|
|
27
|
-
<li class="nav-item" role="presentation">
|
|
28
|
-
<a class="nav-link {{ 'disabled' if not config_list else '' }} {{ 'active' if config_list else '' }}" id="tab4-tab" data-bs-toggle="tab" href="#tab4" role="tab" aria-controls="tab4" aria-selected="false">Configuration</a>
|
|
29
|
-
</li>
|
|
30
|
-
<li class="nav-item" role="presentation">
|
|
31
|
-
<a class="nav-link {{ 'disabled' if not config_list or not return_list else '' }}" id="tab3-tab" data-bs-toggle="tab" href="#tab3" role="tab" aria-controls="tab3" aria-selected="false">Bayesian Optimization</a>
|
|
32
|
-
</li>
|
|
33
|
-
</ul>
|
|
34
|
-
<div class="tab-content" id="myTabsContent">
|
|
35
|
-
<div class="tab-pane fade {{ 'show active' if not config_list else '' }}" id="tab1" role="tabpanel" aria-labelledby="tab1-tab">
|
|
36
|
-
<p><h5>Control panel:</h5></p>
|
|
37
|
-
<form role="form" method='POST' name="run" action="{{url_for('design.experiment_run')}}">
|
|
38
|
-
<div class="input-group mb-3">
|
|
39
|
-
<label class="input-group-text" for="repeat">Repeat for </label>
|
|
40
|
-
<input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="1">
|
|
41
|
-
<label class="input-group-text" for="repeat"> times</label>
|
|
42
|
-
</div>
|
|
43
|
-
<div class="input-group mb-3">
|
|
44
|
-
<button class="form-control" type="submit" class="btn btn-dark">Run</button>
|
|
45
|
-
</div>
|
|
46
|
-
</form>
|
|
47
|
-
</div>
|
|
48
|
-
|
|
49
|
-
{#TODO#}
|
|
50
|
-
<div class="tab-pane fade {{ 'show active' if config_list else '' }}" id="tab4" role="tabpanel" aria-labelledby="tab4-tab">
|
|
51
|
-
<!-- File Management Section -->
|
|
52
|
-
<div class="card mb-4">
|
|
53
|
-
<div class="card-header d-flex justify-content-between align-items-center">
|
|
54
|
-
<h6 class="mb-0"><i class="bi bi-file-earmark-text"></i> Configuration File</h6>
|
|
55
|
-
<small class="text-muted">
|
|
56
|
-
<a href="{{ url_for('design.download', filetype='configure') }}">
|
|
57
|
-
<i class="bi bi-download"></i> Download Empty Template
|
|
58
|
-
</a>
|
|
59
|
-
</small>
|
|
60
|
-
</div>
|
|
61
|
-
<div class="card-body">
|
|
62
|
-
<div class="row g-3">
|
|
63
|
-
<!-- File Selection -->
|
|
64
|
-
<div class="col-md-6">
|
|
65
|
-
<form name="filenameForm" id="filenameForm" method="GET" action="{{ url_for('design.experiment_run') }}" enctype="multipart/form-data">
|
|
66
|
-
<div class="input-group">
|
|
67
|
-
<label class="input-group-text"><i class="bi bi-folder2-open"></i></label>
|
|
68
|
-
<select class="form-select" name="filename" id="filenameSelect" onchange="document.getElementById('filenameForm').submit();">
|
|
69
|
-
<option {{ 'selected' if not filename else '' }} value="">-- Select existing file --</option>
|
|
70
|
-
{% for config_file in config_file_list %}
|
|
71
|
-
<option {{ 'selected' if filename == config_file else '' }} value="{{ config_file }}">{{ config_file }}</option>
|
|
72
|
-
{% endfor %}
|
|
73
|
-
</select>
|
|
74
|
-
</div>
|
|
75
|
-
</form>
|
|
76
|
-
</div>
|
|
77
|
-
|
|
78
|
-
<!-- File Upload -->
|
|
79
|
-
<div class="col-md-6">
|
|
80
|
-
<form method="POST" id="loadFile" name="loadFile" action="{{ url_for('design.upload') }}" enctype="multipart/form-data">
|
|
81
|
-
<div class="input-group">
|
|
82
|
-
<input class="form-control" name="file" type="file" accept=".csv" required="required" onchange="document.getElementById('loadFile').submit();">
|
|
83
|
-
</div>
|
|
84
|
-
</form>
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
</div>
|
|
88
|
-
</div>
|
|
89
|
-
<!-- Configuration Table -->
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
<div class="card mb-4">
|
|
94
|
-
<div class="card-header position-relative">
|
|
95
|
-
<div class="position-absolute top-50 end-0 translate-middle-y me-3">
|
|
96
|
-
<span id="saveStatus" class="badge bg-success" style="display: none;">
|
|
97
|
-
<i class="bi bi-check-circle"></i> Auto-saved
|
|
98
|
-
</span>
|
|
99
|
-
<span id="modifiedStatus" class="badge bg-warning" style="display: none;">
|
|
100
|
-
<i class="bi bi-pencil"></i> Modified
|
|
101
|
-
</span>
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
<div class="card-body p-0">
|
|
105
|
-
<form method="POST" name="online-config" id="online-config" action="{{url_for('design.experiment_run')}}">
|
|
106
|
-
<div class="table-responsive">
|
|
107
|
-
<table id="dataInputTable" class="table table-striped table-hover mb-0">
|
|
108
|
-
<thead class="table-dark">
|
|
109
|
-
<tr>
|
|
110
|
-
<th style="width: 40px;">#</th>
|
|
111
|
-
{% for column in config_list %}
|
|
112
|
-
<th>{{ column }}</th>
|
|
113
|
-
{% endfor %}
|
|
114
|
-
<th></th>
|
|
115
|
-
</tr>
|
|
116
|
-
</thead>
|
|
117
|
-
<tbody id="tableBody">
|
|
118
|
-
</tbody>
|
|
119
|
-
</table>
|
|
120
|
-
</div>
|
|
121
|
-
<div class="card-footer">
|
|
122
|
-
<div class="d-flex justify-content-between align-items-center">
|
|
123
|
-
<div class="d-flex gap-2">
|
|
124
|
-
<button type="button" class="btn btn-success" onclick="addRow()">
|
|
125
|
-
<i class="bi bi-plus-circle"></i> Add Row
|
|
126
|
-
</button>
|
|
127
|
-
<button type="button" class="btn btn-warning" onclick="clearAllRows()">
|
|
128
|
-
<i class="bi bi-trash"></i> Clear All
|
|
129
|
-
</button>
|
|
130
|
-
<button type="button" class="btn btn-info" onclick="resetToFile()" id="resetToFileBtn" style="display: none;">
|
|
131
|
-
<i class="bi bi-arrow-clockwise"></i> Reset to File
|
|
132
|
-
</button>
|
|
133
|
-
</div>
|
|
134
|
-
<button type="submit" name="online-config" class="btn btn-primary btn-lg">
|
|
135
|
-
<i class="bi bi-play-circle"></i> Run
|
|
136
|
-
</button>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
</form>
|
|
140
|
-
</div>
|
|
141
|
-
<!-- Config Preview (if loaded from file) -->
|
|
142
|
-
{% if config_preview %}
|
|
143
|
-
<div class="alert alert-info">
|
|
144
|
-
<small><i class="bi bi-info-circle"></i> {{ config_preview|length }} rows loaded from {{ filename }}</small>
|
|
145
|
-
</div>
|
|
146
|
-
{% endif %}
|
|
147
|
-
</div>
|
|
148
|
-
</div>
|
|
149
|
-
|
|
150
|
-
<div class="tab-pane fade" id="tab3" role="tabpanel" aria-labelledby="tab3-tab">
|
|
151
|
-
<form method="POST" name="bo" action="{{ url_for('design.experiment_run') }}">
|
|
152
|
-
<div class="container py-2">
|
|
153
|
-
<!-- Parameters -->
|
|
154
|
-
<h6 class="fw-bold mt-2 mb-1">Parameters</h6>
|
|
155
|
-
{% for config in config_list %}
|
|
156
|
-
<div class="row align-items-center mb-2">
|
|
157
|
-
<div class="col-3 col-form-label-sm">
|
|
158
|
-
{{ config }}:
|
|
159
|
-
</div>
|
|
160
|
-
<div class="col-6">
|
|
161
|
-
<select class="form-select form-select-sm" id="{{config}}_type" name="{{config}}_type">
|
|
162
|
-
<option selected value="range">range</option>
|
|
163
|
-
<option value="choice">choice</option>
|
|
164
|
-
<option value="fixed">fixed</option>
|
|
165
|
-
</select>
|
|
166
|
-
</div>
|
|
167
|
-
<div class="col-3">
|
|
168
|
-
<input type="text" class="form-control form-control-sm" id="{{config}}_value" name="{{config}}_value" placeholder="1, 2, 3">
|
|
169
|
-
</div>
|
|
170
|
-
</div>
|
|
171
|
-
{% endfor %}
|
|
172
|
-
<!-- Objective -->
|
|
173
|
-
<h6 class="fw-bold mt-3 mb-1">Objectives</h6>
|
|
174
|
-
{% for objective in return_list %}
|
|
175
|
-
<div class="row align-items-center mb-2">
|
|
176
|
-
<div class="col-3 col-form-label-sm">
|
|
177
|
-
{{ objective }}:
|
|
178
|
-
</div>
|
|
179
|
-
<div class="col-6">
|
|
180
|
-
<select class="form-select form-select-sm" id="{{objective}}_min" name="{{objective}}_min">
|
|
181
|
-
<option selected>minimize</option>
|
|
182
|
-
<option>maximize</option>
|
|
183
|
-
<option>none</option>
|
|
184
|
-
</select>
|
|
185
|
-
</div>
|
|
186
|
-
</div>
|
|
187
|
-
{% endfor %}
|
|
188
|
-
<h6 class="fw-bold mt-3 mb-1">Budget</h6>
|
|
189
|
-
<div class="input-group mb-3">
|
|
190
|
-
<label class="input-group-text" for="repeat">Max iteration </label>
|
|
191
|
-
<input class="form-control" type="number" id="repeat" name="repeat" min="1" max="1000" value="25">
|
|
192
|
-
</div>
|
|
193
|
-
{% if not no_deck_warning%}
|
|
194
|
-
<div class="input-group mb-3">
|
|
195
|
-
<button class="form-control" type="submit" name="bo">Run</button>
|
|
196
|
-
</div>
|
|
197
|
-
{% endif %}
|
|
198
|
-
</div>
|
|
199
|
-
</form>
|
|
200
|
-
</div>
|
|
201
|
-
</div>
|
|
202
|
-
</div>
|
|
203
|
-
{% else %}
|
|
204
|
-
<div class="col-lg-6 col-sm-12" id="placeholder-panel">
|
|
205
|
-
</div>
|
|
206
|
-
{% endif %}
|
|
207
|
-
|
|
208
|
-
<div class="col-lg-6 col-sm-12" id="code-panel" style="{{ '' if pause_status else 'display: none;'}}">
|
|
209
|
-
<p>
|
|
210
|
-
<h5>Progress:</h5>
|
|
211
|
-
{% if "prep" in line_collection.keys() %}
|
|
212
|
-
{% set stype = "prep" %}
|
|
213
|
-
<h6>Preparation:</h6>
|
|
214
|
-
{% for code in line_collection["prep"] %}
|
|
215
|
-
<pre style="margin: 0; padding: 0; line-height: 1;"><code class="python" id="{{ stype }}-{{ loop.index0 }}" >{{code}}</code></pre>
|
|
216
|
-
{% endfor %}
|
|
217
|
-
{% endif %}
|
|
218
|
-
{% if "script" in line_collection.keys() %}
|
|
219
|
-
{% set stype = "script" %}
|
|
220
|
-
<h6>Experiment:</h6>
|
|
221
|
-
{% for code in line_collection["script"] %}
|
|
222
|
-
<pre style="margin: 0; padding: 0; line-height: 1;"><code class="python" id="{{ stype }}-{{ loop.index0 }}" >{{code}}</code></pre>
|
|
223
|
-
{% endfor %}
|
|
224
|
-
{% endif %}
|
|
225
|
-
{% if "cleanup" in line_collection.keys() %}
|
|
226
|
-
{% set stype = "cleanup" %}
|
|
227
|
-
<h6>Cleanup:</h6>
|
|
228
|
-
{% for code in line_collection["cleanup"] %}
|
|
229
|
-
<pre style="margin: 0; padding: 0; line-height: 1;"><code class="python" id="{{ stype }}-{{ loop.index0 }}" >{{code}}</code></pre>
|
|
230
|
-
{% endfor %}
|
|
231
|
-
{% endif %}
|
|
232
|
-
</p>
|
|
233
|
-
</div>
|
|
234
|
-
<div class="col-lg-6 col-sm-12 logging-panel">
|
|
235
|
-
<p>
|
|
236
|
-
<div class="p d-flex justify-content-between align-items-center">
|
|
237
|
-
<h5>Progress:</h5>
|
|
238
|
-
<div class="d-flex gap-2 ms-auto">
|
|
239
|
-
<button id="pause-resume" class="btn btn-info text-white" data-bs-toggle="tooltip" title="Pause execution">
|
|
240
|
-
{% if pause_status %}
|
|
241
|
-
<i class="bi bi-play-circle"></i>
|
|
242
|
-
{% else %}
|
|
243
|
-
<i class="bi bi-pause-circle"></i>
|
|
244
|
-
{% endif %}
|
|
245
|
-
</button>
|
|
246
|
-
<button id="abort-current" class="btn btn-danger text-white" data-bs-toggle="tooltip" title="Stop execution after current step">
|
|
247
|
-
<i class="bi bi-stop-circle"></i>
|
|
248
|
-
</button>
|
|
249
|
-
<button id="abort-pending" class="btn btn-warning text-white" data-bs-toggle="tooltip" title="Stop execution after current iteration">
|
|
250
|
-
<i class="bi bi-hourglass-split"></i>
|
|
251
|
-
</button>
|
|
252
|
-
</div>
|
|
253
|
-
</div>
|
|
254
|
-
<div class="text-muted mt-2">
|
|
255
|
-
<small><strong>Note:</strong> The current step cannot be paused or stopped until it completes. </small>
|
|
256
|
-
</div>
|
|
257
|
-
|
|
258
|
-
<div class="progress" role="progressbar" aria-label="Animated striped example" aria-valuenow="10" aria-valuemin="0" aria-valuemax="100">
|
|
259
|
-
<div id="progress-bar-inner" class="progress-bar progress-bar-striped progress-bar-animated"></div>
|
|
260
|
-
</div>
|
|
261
|
-
<p><h5>Log:</h5></p>
|
|
262
|
-
<div id="logging-panel"></div>
|
|
263
|
-
</div>
|
|
264
|
-
|
|
265
|
-
</div>
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
<!-- Error Modal -->
|
|
272
|
-
<div class="modal fade" id="error-modal" tabindex="-1" aria-labelledby="errorModalLabel" aria-hidden="true">
|
|
273
|
-
<div class="modal-dialog">
|
|
274
|
-
<div class="modal-content">
|
|
275
|
-
<div class="modal-header">
|
|
276
|
-
<h5 class="modal-title" id="errorModalLabel">Error Detected</h5>
|
|
277
|
-
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
278
|
-
</div>
|
|
279
|
-
<div class="modal-body">
|
|
280
|
-
<p id="error-message">An error has occurred.</p>
|
|
281
|
-
<p>Do you want to continue execution or stop?</p>
|
|
282
|
-
</div>
|
|
283
|
-
<div class="modal-footer">
|
|
284
|
-
<button type="button" class="btn btn-primary" id="retry-btn" data-bs-dismiss="modal">Rerun Current Step</button>
|
|
285
|
-
<button type="button" class="btn btn-success" id="continue-btn" data-bs-dismiss="modal">Continue</button>
|
|
286
|
-
<button type="button" class="btn btn-danger" id="stop-btn" data-bs-dismiss="modal">Stop Execution</button>
|
|
287
|
-
</div>
|
|
288
|
-
</div>
|
|
289
|
-
</div>
|
|
290
|
-
</div>
|
|
291
|
-
|
|
292
|
-
<script src="{{ url_for('static', filename='js/socket_handler.js') }}"></script>
|
|
293
|
-
<script>
|
|
294
|
-
var rowCount = 0;
|
|
295
|
-
var configColumns = [
|
|
296
|
-
{% for column in config_list %}
|
|
297
|
-
'{{ column }}'{{ ',' if not loop.last else '' }}
|
|
298
|
-
{% endfor %}
|
|
299
|
-
];
|
|
300
|
-
var configTypes = {
|
|
301
|
-
{% for column, type in config_type_list.items() %}
|
|
302
|
-
'{{ column }}': '{{ type }}'{{ ',' if not loop.last else '' }}
|
|
303
|
-
{% endfor %}
|
|
304
|
-
};
|
|
305
|
-
|
|
306
|
-
// State management
|
|
307
|
-
var originalFileData = null;
|
|
308
|
-
var isModifiedFromFile = false;
|
|
309
|
-
var saveTimeout = null;
|
|
310
|
-
var lastSavedData = null;
|
|
311
|
-
|
|
312
|
-
function addRow(data = null, skipSave = false) {
|
|
313
|
-
rowCount++;
|
|
314
|
-
var tableBody = document.getElementById("tableBody");
|
|
315
|
-
var newRow = tableBody.insertRow(-1);
|
|
316
|
-
|
|
317
|
-
// Row number cell
|
|
318
|
-
var rowNumCell = newRow.insertCell(-1);
|
|
319
|
-
rowNumCell.innerHTML = '<span class="badge bg-secondary">' + rowCount + '</span>';
|
|
320
|
-
|
|
321
|
-
// Data cells
|
|
322
|
-
configColumns.forEach(function(column, index) {
|
|
323
|
-
var cell = newRow.insertCell(-1);
|
|
324
|
-
var value = data && data[column] ? data[column] : '';
|
|
325
|
-
var placeholder = configTypes[column] || 'value';
|
|
326
|
-
cell.innerHTML = '<input type="text" class="form-control form-control-sm" name="' +
|
|
327
|
-
column + '[' + rowCount + ']" value="' + value + '" placeholder="' + placeholder +
|
|
328
|
-
'" oninput="onInputChange()" onchange="onInputChange()">';
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
// Action cell
|
|
332
|
-
var actionCell = newRow.insertCell(-1);
|
|
333
|
-
actionCell.innerHTML = '<button type="button" class="btn btn-sm btn-outline-danger" onclick="removeRow(this)" title="Remove row">' +
|
|
334
|
-
'<i class="bi bi-trash"></i></button>';
|
|
335
|
-
|
|
336
|
-
if (!skipSave) {
|
|
337
|
-
markAsModified();
|
|
338
|
-
debouncedSave();
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function removeRow(button) {
|
|
343
|
-
var row = button.closest('tr');
|
|
344
|
-
row.remove();
|
|
345
|
-
updateRowNumbers();
|
|
346
|
-
markAsModified();
|
|
347
|
-
debouncedSave();
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
function updateRowNumbers() {
|
|
351
|
-
var tableBody = document.getElementById("tableBody");
|
|
352
|
-
var rows = tableBody.getElementsByTagName('tr');
|
|
353
|
-
for (var i = 0; i < rows.length; i++) {
|
|
354
|
-
var badge = rows[i].querySelector('.badge');
|
|
355
|
-
if (badge) {
|
|
356
|
-
badge.textContent = i + 1;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
function clearAllRows() {
|
|
362
|
-
if (confirm('Are you sure you want to clear all rows?')) {
|
|
363
|
-
var tableBody = document.getElementById("tableBody");
|
|
364
|
-
tableBody.innerHTML = '';
|
|
365
|
-
rowCount = 0;
|
|
366
|
-
markAsModified();
|
|
367
|
-
clearSavedData();
|
|
368
|
-
// Add 5 empty rows by default
|
|
369
|
-
for (let i = 0; i < 5; i++) {
|
|
370
|
-
addRow(null, true);
|
|
371
|
-
}
|
|
372
|
-
debouncedSave();
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function resetToFile() {
|
|
377
|
-
if (originalFileData && confirm('Reset to original file data? This will lose all manual changes.')) {
|
|
378
|
-
loadDataFromSource(originalFileData, false);
|
|
379
|
-
isModifiedFromFile = false;
|
|
380
|
-
updateStatusIndicators();
|
|
381
|
-
debouncedSave();
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
function onInputChange() {
|
|
386
|
-
markAsModified();
|
|
387
|
-
debouncedSave();
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
function markAsModified() {
|
|
391
|
-
if (originalFileData) {
|
|
392
|
-
isModifiedFromFile = true;
|
|
393
|
-
updateStatusIndicators();
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function updateStatusIndicators() {
|
|
398
|
-
var modifiedStatus = document.getElementById('modifiedStatus');
|
|
399
|
-
var resetBtn = document.getElementById('resetToFileBtn');
|
|
400
|
-
|
|
401
|
-
if (isModifiedFromFile && originalFileData) {
|
|
402
|
-
modifiedStatus.style.display = 'inline-block';
|
|
403
|
-
resetBtn.style.display = 'inline-block';
|
|
404
|
-
} else {
|
|
405
|
-
modifiedStatus.style.display = 'none';
|
|
406
|
-
resetBtn.style.display = 'none';
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
function showSaveStatus() {
|
|
411
|
-
var saveStatus = document.getElementById('saveStatus');
|
|
412
|
-
saveStatus.style.display = 'inline-block';
|
|
413
|
-
setTimeout(function() {
|
|
414
|
-
saveStatus.style.display = 'none';
|
|
415
|
-
}, 2000);
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
function debouncedSave() {
|
|
419
|
-
clearTimeout(saveTimeout);
|
|
420
|
-
saveTimeout = setTimeout(function() {
|
|
421
|
-
saveFormData();
|
|
422
|
-
showSaveStatus();
|
|
423
|
-
}, 1000); // Save 1 second after user stops typing
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function saveFormData() {
|
|
427
|
-
var formData = getCurrentFormData();
|
|
428
|
-
try {
|
|
429
|
-
sessionStorage.setItem('configFormData', JSON.stringify(formData));
|
|
430
|
-
sessionStorage.setItem('configModified', isModifiedFromFile.toString());
|
|
431
|
-
lastSavedData = formData;
|
|
432
|
-
} catch (e) {
|
|
433
|
-
console.warn('Could not save form data to sessionStorage:', e);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
function getCurrentFormData() {
|
|
438
|
-
var tableBody = document.getElementById("tableBody");
|
|
439
|
-
var rows = tableBody.getElementsByTagName('tr');
|
|
440
|
-
var data = [];
|
|
441
|
-
|
|
442
|
-
for (var i = 0; i < rows.length; i++) {
|
|
443
|
-
var inputs = rows[i].getElementsByTagName('input');
|
|
444
|
-
var rowData = {};
|
|
445
|
-
var hasData = false;
|
|
446
|
-
|
|
447
|
-
for (var j = 0; j < inputs.length; j++) {
|
|
448
|
-
var input = inputs[j];
|
|
449
|
-
var name = input.name;
|
|
450
|
-
if (name) {
|
|
451
|
-
var columnName = name.substring(0, name.indexOf('['));
|
|
452
|
-
rowData[columnName] = input.value;
|
|
453
|
-
if (input.value.trim() !== '') {
|
|
454
|
-
hasData = true;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (hasData) {
|
|
460
|
-
data.push(rowData);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
return data;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
function loadSavedData() {
|
|
468
|
-
try {
|
|
469
|
-
var savedData = sessionStorage.getItem('configFormData');
|
|
470
|
-
var savedModified = sessionStorage.getItem('configModified');
|
|
471
|
-
|
|
472
|
-
if (savedData) {
|
|
473
|
-
var parsedData = JSON.parse(savedData);
|
|
474
|
-
isModifiedFromFile = savedModified === 'true';
|
|
475
|
-
return parsedData;
|
|
476
|
-
}
|
|
477
|
-
} catch (e) {
|
|
478
|
-
console.warn('Could not load saved form data:', e);
|
|
479
|
-
}
|
|
480
|
-
return null;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
function clearSavedData() {
|
|
484
|
-
try {
|
|
485
|
-
sessionStorage.removeItem('configFormData');
|
|
486
|
-
sessionStorage.removeItem('configModified');
|
|
487
|
-
} catch (e) {
|
|
488
|
-
console.warn('Could not clear saved data:', e);
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
function loadDataFromSource(data, isFromFile = false) {
|
|
493
|
-
// Clear existing rows
|
|
494
|
-
var tableBody = document.getElementById("tableBody");
|
|
495
|
-
tableBody.innerHTML = '';
|
|
496
|
-
rowCount = 0;
|
|
497
|
-
|
|
498
|
-
// Add rows with data
|
|
499
|
-
data.forEach(function(rowData) {
|
|
500
|
-
addRow(rowData, true);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// Add a few empty rows for additional input
|
|
504
|
-
for (let i = 0; i < 3; i++) {
|
|
505
|
-
addRow(null, true);
|
|
506
|
-
}
|
|
507
|
-
|
|
508
|
-
if (isFromFile) {
|
|
509
|
-
originalFileData = JSON.parse(JSON.stringify(data)); // Deep copy
|
|
510
|
-
isModifiedFromFile = false;
|
|
511
|
-
clearSavedData(); // Clear saved data when loading from file
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
updateStatusIndicators();
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
function loadConfigData() {
|
|
518
|
-
// Check for saved form data first
|
|
519
|
-
var savedData = loadSavedData();
|
|
520
|
-
|
|
521
|
-
{% if config_preview %}
|
|
522
|
-
var fileData = {{ config_preview | tojson | safe }};
|
|
523
|
-
originalFileData = JSON.parse(JSON.stringify(fileData)); // Deep copy
|
|
524
|
-
|
|
525
|
-
if (savedData && savedData.length > 0) {
|
|
526
|
-
// Load saved data if available
|
|
527
|
-
loadDataFromSource(savedData, false);
|
|
528
|
-
console.log('Loaded saved form data');
|
|
529
|
-
} else {
|
|
530
|
-
// Load from file
|
|
531
|
-
loadDataFromSource(fileData, true);
|
|
532
|
-
console.log('Loaded file data');
|
|
533
|
-
}
|
|
534
|
-
{% else %}
|
|
535
|
-
if (savedData && savedData.length > 0) {
|
|
536
|
-
// Load saved data
|
|
537
|
-
loadDataFromSource(savedData, false);
|
|
538
|
-
console.log('Loaded saved form data');
|
|
539
|
-
} else {
|
|
540
|
-
// Add default empty rows
|
|
541
|
-
for (let i = 0; i < 5; i++) {
|
|
542
|
-
addRow(null, true);
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
{% endif %}
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// Handle page unload
|
|
549
|
-
window.addEventListener('beforeunload', function() {
|
|
550
|
-
saveFormData();
|
|
551
|
-
});
|
|
552
|
-
|
|
553
|
-
// Initialize table when page loads
|
|
554
|
-
document.addEventListener("DOMContentLoaded", function() {
|
|
555
|
-
loadConfigData();
|
|
556
|
-
});
|
|
557
|
-
</script>
|
|
558
|
-
{% endblock %}
|
ivoryos-1.0.9.dist-info/RECORD
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
ivoryos/__init__.py,sha256=SEy7z9DYSYfSTDlBh8SuqEvBMkalkzeEpB-iE5WyBsI,8136
|
|
2
|
-
ivoryos/config.py,sha256=sk4dskm-K_Nv4uaA3QuE6xtew8wL6q3HmIoLgRm7p8U,2153
|
|
3
|
-
ivoryos/version.py,sha256=q2ACMkQx0Hm5xKo2YKJFBE7rTruciTSIN6AvWWL9nB8,22
|
|
4
|
-
ivoryos/routes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
ivoryos/routes/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
ivoryos/routes/auth/auth.py,sha256=pvrYQN2XqH2OpZMxirFQZr9-c8yO29CpvQg9VR6JFsE,3256
|
|
7
|
-
ivoryos/routes/auth/templates/auth/login.html,sha256=WSRrKbdM_oobqSXFRTo-j9UlOgp6sYzS9tm7TqqPULI,1207
|
|
8
|
-
ivoryos/routes/auth/templates/auth/signup.html,sha256=b5LTXtpfTSkSS7X8u1ldwQbbgEFTk6UNMAediA5BwBY,1465
|
|
9
|
-
ivoryos/routes/control/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
|
-
ivoryos/routes/control/control.py,sha256=AaXqXqaIIed9xBVQsk52CNnNDTSofje5qQAfDGWd1Q0,16404
|
|
11
|
-
ivoryos/routes/control/templates/control/controllers.html,sha256=iIp0h6WA68gQj9OsoiB7dU1BqH8CGomTueR73F4C8eY,4274
|
|
12
|
-
ivoryos/routes/control/templates/control/controllers_home.html,sha256=qAM4iZBEuXvSgGUWWVVIe2E9MPJOeG7U214hYM84jIE,2976
|
|
13
|
-
ivoryos/routes/control/templates/control/controllers_new.html,sha256=uOQo9kYmwX2jk3KZDkMUF_ylfNUIs_oIWb_kk_MMVDM,4921
|
|
14
|
-
ivoryos/routes/database/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
ivoryos/routes/database/database.py,sha256=JwFuWf9WHju0CepkuSz6OaOwV6O2f76Vv_0myCFMPFc,9833
|
|
16
|
-
ivoryos/routes/database/templates/database/scripts_database.html,sha256=tEpKOj1UGz7mcDq11guwP48XJxwawjxjPvxRhKiIG2I,3640
|
|
17
|
-
ivoryos/routes/database/templates/database/step_card.html,sha256=F4JRfacrEQfk2rrEbcI_i7G84nzKKDmCrMSmStLb4W4,290
|
|
18
|
-
ivoryos/routes/database/templates/database/workflow_database.html,sha256=fsJHrYeEHGBKRn1pIxWITE6e93tdZsXH3zRs9Ob5FX0,4467
|
|
19
|
-
ivoryos/routes/database/templates/database/workflow_view.html,sha256=u8_XYhiZ98PzglMzFEkuM1Tk9hVWf79xXIrpHVDxKa0,3618
|
|
20
|
-
ivoryos/routes/design/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
21
|
-
ivoryos/routes/design/design.py,sha256=ui9GvLoJ-0XNZT6q13KPgDh4NEEbVxaHKYcBtDqEkao,29866
|
|
22
|
-
ivoryos/routes/design/templates/design/experiment_builder.html,sha256=4JjkwdMAWZA1XrGtoqBKykDikf-Qg7RbjqedqY_J-fU,32326
|
|
23
|
-
ivoryos/routes/design/templates/design/experiment_run.html,sha256=UFqg6GMgkyYJfc1Ifg1jhyJggdZkCYpgQrNotiXWzwc,25582
|
|
24
|
-
ivoryos/routes/main/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
25
|
-
ivoryos/routes/main/main.py,sha256=yuVJzXAob1kc1dfflkTBIZQ0tdf6kChfuq-uQlN1e9Q,957
|
|
26
|
-
ivoryos/routes/main/templates/main/help.html,sha256=IOktMEsOPk0SCiMBXZ4mpffClERAyX8W82fel71M3M0,9370
|
|
27
|
-
ivoryos/routes/main/templates/main/home.html,sha256=8AhQOWakD-1TyWA0s-B9ZK96L_f8ywYUEGHW1UzMGZA,4634
|
|
28
|
-
ivoryos/static/favicon.ico,sha256=RhlrPtfITOkzC9BjP1UB1V5L9Oyp6NwNtWeMcGOnpyc,15406
|
|
29
|
-
ivoryos/static/logo.webp,sha256=lXgfQR-4mHTH83k7VV9iB54-oC2ipe6uZvbwdOnLETc,14974
|
|
30
|
-
ivoryos/static/style.css,sha256=zQVx35A5g6JMJ-K84-6fSKtzXGjp_p5ZVG6KLHPM2IE,4021
|
|
31
|
-
ivoryos/static/gui_annotation/Slide1.png,sha256=Lm4gdOkUF5HIUFaB94tl6koQVkzpitKj43GXV_XYMMc,121727
|
|
32
|
-
ivoryos/static/gui_annotation/Slide2.PNG,sha256=z3wQ9oVgg4JTWVLQGKK_KhtepRHUYP1e05XUWGT2A0I,118761
|
|
33
|
-
ivoryos/static/js/overlay.js,sha256=dPxop19es0E0ZUSY3d_4exIk7CJuQEnlW5uTt5fZfzI,483
|
|
34
|
-
ivoryos/static/js/socket_handler.js,sha256=2Iyv_3METjhSlSavs_L9FE3PKY4xDEpfzJpd2FywY9o,5300
|
|
35
|
-
ivoryos/static/js/sortable_card.js,sha256=ifmlGe3yy0U_KzMphV4ClRhK2DLOvkELYMlq1vECuac,807
|
|
36
|
-
ivoryos/static/js/sortable_design.js,sha256=d55AEz8LpPX_j-hREom-I19i4l-SOG2RVSR4CnozRtY,4366
|
|
37
|
-
ivoryos/templates/base.html,sha256=sDdwqOIUP2Get-py4E59PkieoGWLFpX6wAJe93s4aRo,8518
|
|
38
|
-
ivoryos/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
|
-
ivoryos/utils/bo_campaign.py,sha256=CVs7q15Pm2SRuJNaCvZKIxOFuv1xibM2yymtpAMAWOk,3285
|
|
40
|
-
ivoryos/utils/client_proxy.py,sha256=0OT2xTMkqh_2ybgCxMV_71ZVUThWwrsnAhTIBY5vDR8,2095
|
|
41
|
-
ivoryos/utils/db_models.py,sha256=HQSjMrZc1o1fvjx5Mf7W_53xPbT9aZ00xtUJJNPbwio,27502
|
|
42
|
-
ivoryos/utils/form.py,sha256=k9d4AZz74FeOh4gkhDsZx3g4LZti_aJm9ZPRBkpOsE0,21933
|
|
43
|
-
ivoryos/utils/global_config.py,sha256=OqfDrPgOzRdIUMD4V3pA9t6b-BATMjGZl8Jn7nkI56k,2138
|
|
44
|
-
ivoryos/utils/llm_agent.py,sha256=-lVCkjPlpLues9sNTmaT7bT4sdhWvV2DiojNwzB2Lcw,6422
|
|
45
|
-
ivoryos/utils/script_runner.py,sha256=0b5hLKAF2o0SQKiArhUsG8-4MA-eniAcjwi8gCNVwtY,14542
|
|
46
|
-
ivoryos/utils/task_runner.py,sha256=u4nF0wOADu_HVlGYVTOXnUm1woWGgYAccr-ZCzgtb6Q,2899
|
|
47
|
-
ivoryos/utils/utils.py,sha256=BzgKIMMb7vyUIwYMhGDsWtwJEy5vNKtEHRJHHSiTSnM,13881
|
|
48
|
-
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
49
|
-
tests/conftest.py,sha256=u2sQ6U-Lghyl7et1Oz6J2E5VZ47VINKcjRM_2leAE2s,3627
|
|
50
|
-
tests/integration/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
51
|
-
tests/integration/test_route_auth.py,sha256=l3ZDqr0oiCWS3yYSXGK5yMP6qI2t7Sv5I9zoYTkiyQU,2754
|
|
52
|
-
tests/integration/test_route_control.py,sha256=YYIll84bTUEKiAxFiFSz6LF3fTldPNfCtHs0IR3mSdM,3935
|
|
53
|
-
tests/integration/test_route_database.py,sha256=mS026W_hEuCTMpSkdRWvM-f4MYykK_6nRDJ4K5a7QA0,2342
|
|
54
|
-
tests/integration/test_route_design.py,sha256=PJAvGRiCY6B53Pu1v5vPAVHHsuaqRmRKk2eesSNshLU,1157
|
|
55
|
-
tests/integration/test_route_main.py,sha256=bmuf8Y_9CRWhiLLf4up11ltEd5YCdsLx6I-o26VGDEw,1228
|
|
56
|
-
tests/integration/test_sockets.py,sha256=4ZyFyExm7a-DYzVqpzEONpWeb1a0IT68wyFaQu0rY_Y,925
|
|
57
|
-
ivoryos-1.0.9.dist-info/LICENSE,sha256=p2c8S8i-8YqMpZCJnadLz1-ofxnRMILzz6NCMIypRag,1084
|
|
58
|
-
ivoryos-1.0.9.dist-info/METADATA,sha256=hQZ8qTQfJGOrlFzsPj364ZTGKpgEeW0FKs7DJXqIbQc,8931
|
|
59
|
-
ivoryos-1.0.9.dist-info/WHEEL,sha256=tZoeGjtWxWRfdplE7E3d45VPlLNQnvbKiYnx7gwAy8A,92
|
|
60
|
-
ivoryos-1.0.9.dist-info/top_level.txt,sha256=mIOiZkdpSwxFJt1R5fsyOff8mNprXHq1nMGNKNULIyE,14
|
|
61
|
-
ivoryos-1.0.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|