aind-data-transfer-service 1.17.0__py3-none-any.whl → 1.17.2__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.
- aind_data_transfer_service/__init__.py +1 -1
- aind_data_transfer_service/hpc/client.py +28 -25
- aind_data_transfer_service/server.py +68 -57
- {aind_data_transfer_service-1.17.0.dist-info → aind_data_transfer_service-1.17.2.dist-info}/METADATA +1 -1
- aind_data_transfer_service-1.17.2.dist-info/RECORD +18 -0
- aind_data_transfer_service/templates/admin.html +0 -45
- aind_data_transfer_service/templates/index.html +0 -258
- aind_data_transfer_service/templates/job_params.html +0 -405
- aind_data_transfer_service/templates/job_status.html +0 -324
- aind_data_transfer_service/templates/job_tasks_table.html +0 -146
- aind_data_transfer_service/templates/task_logs.html +0 -31
- aind_data_transfer_service-1.17.0.dist-info/RECORD +0 -24
- {aind_data_transfer_service-1.17.0.dist-info → aind_data_transfer_service-1.17.2.dist-info}/WHEEL +0 -0
- {aind_data_transfer_service-1.17.0.dist-info → aind_data_transfer_service-1.17.2.dist-info}/licenses/LICENSE +0 -0
- {aind_data_transfer_service-1.17.0.dist-info → aind_data_transfer_service-1.17.2.dist-info}/top_level.txt +0 -0
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
6
|
-
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.8.1/font/bootstrap-icons.min.css" rel="stylesheet">
|
|
7
|
-
<link rel="stylesheet" href="https://cdn.datatables.net/2.1.8/css/dataTables.dataTables.css" />
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
9
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
|
|
10
|
-
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
|
|
11
|
-
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
|
|
12
|
-
<script src="https://cdn.datatables.net/2.1.8/js/dataTables.js"></script>
|
|
13
|
-
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
|
|
14
|
-
<title>{% block title %} {% endblock %} AIND Data Transfer Service Jobs</title>
|
|
15
|
-
<style>
|
|
16
|
-
body {
|
|
17
|
-
margin: 20px;
|
|
18
|
-
font-family: arial, sans-serif;
|
|
19
|
-
}
|
|
20
|
-
nav {
|
|
21
|
-
height: 40px;
|
|
22
|
-
}
|
|
23
|
-
.modal-body {
|
|
24
|
-
height: calc(100vh - 100px);
|
|
25
|
-
}
|
|
26
|
-
</style>
|
|
27
|
-
</head>
|
|
28
|
-
<body>
|
|
29
|
-
<nav>
|
|
30
|
-
<a href="/">Submit Jobs</a> |
|
|
31
|
-
<a href="/jobs">Job Status</a> |
|
|
32
|
-
<a href="/job_params">Job Parameters</a> |
|
|
33
|
-
<a title="Download job template as .xslx" href= "/api/job_upload_template" download>Job Submit Template</a> |
|
|
34
|
-
<a title="List of project names" href= "{{ project_names_url }}" target="_blank" >Project Names</a> |
|
|
35
|
-
<a title="For more information click here" href="https://aind-data-transfer-service.readthedocs.io" target="_blank" >Help</a> |
|
|
36
|
-
<a href="/admin">Admin</a>
|
|
37
|
-
</nav>
|
|
38
|
-
<div class="content">
|
|
39
|
-
<!-- display total entries -->
|
|
40
|
-
<h4 class="mb-2">Jobs Submitted: <span id="total-entries"></span></h4>
|
|
41
|
-
<!-- filters for job status results-->
|
|
42
|
-
<div class="card mb-4 small" style="width:400px">
|
|
43
|
-
<div class="card-header py-1" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-filters" aria-expanded="false" aria-controls="collapse-filters">
|
|
44
|
-
<i class="bi bi-filter"></i><span class="ms-2">Filter by</span>
|
|
45
|
-
<i class="bi bi-chevron-expand float-end"></i>
|
|
46
|
-
</div>
|
|
47
|
-
<div id="collapse-filters" class="collapse card-body p-2">
|
|
48
|
-
<!-- filter by job status -->
|
|
49
|
-
<div class="input-group input-group-sm mb-1">
|
|
50
|
-
<span class="input-group-text" style="width:35%">Status</span>
|
|
51
|
-
<select class="form-select" onchange="filterJobsByColumn(4, this.value);this.blur();">
|
|
52
|
-
{% for s in [
|
|
53
|
-
{"label": "all", "value": "", "class": "text-dark"},
|
|
54
|
-
{"label": "queued", "value": "queued", "class": "text-secondary"},
|
|
55
|
-
{"label": "running", "value": "running", "class": "text-info"},
|
|
56
|
-
{"label": "failed", "value": "failed", "class": "text-danger"},
|
|
57
|
-
{"label": "success", "value": "success", "class": "text-success"},
|
|
58
|
-
] %}
|
|
59
|
-
<option class="{{ s.class }}" value="{{ s.value }}">{{ s.label }}</option>
|
|
60
|
-
{% endfor %}
|
|
61
|
-
</select>
|
|
62
|
-
</div>
|
|
63
|
-
<!-- filter by job submitted date range -->
|
|
64
|
-
<div class="input-group input-group-sm">
|
|
65
|
-
<span class="input-group-text" style="width:35%">Submit Time</span>
|
|
66
|
-
<input id="submit-date-range" class="form-select" type="text" />
|
|
67
|
-
</div>
|
|
68
|
-
<!-- filter by asset name -->
|
|
69
|
-
<hr class="flex-grow-1 border-secondary">
|
|
70
|
-
<div class="input-group input-group-sm mb-1">
|
|
71
|
-
<span class="input-group-text" style="width:35%">Asset Name</span>
|
|
72
|
-
<input id="filter-name-input" type="text" class="form-control" placeholder="asset name" oninput="filterJobsByColumn(0, this.value)">
|
|
73
|
-
<button id="filter-name-clear" class="btn btn-outline-secondary" type="button" title="Clear" onclick="clearFilterJobsByColumn(0, '#filter-name-input')">
|
|
74
|
-
<i class="bi bi-x-lg"></i>
|
|
75
|
-
</button>
|
|
76
|
-
</div>
|
|
77
|
-
<!-- filter by job id-->
|
|
78
|
-
<div class="input-group input-group-sm mb-1">
|
|
79
|
-
<span class="input-group-text" style="width:35%">Job ID</span>
|
|
80
|
-
<input id="filter-id-input" type="text" class="form-control" placeholder="job id" oninput="filterJobsByColumn(1, this.value)">
|
|
81
|
-
<button id="filter-id-clear" class="btn btn-outline-secondary" type="button" title="Clear" onclick="clearFilterJobsByColumn(1, '#filter-id-input')">
|
|
82
|
-
<i class="bi bi-x-lg"></i>
|
|
83
|
-
</button>
|
|
84
|
-
</div>
|
|
85
|
-
<!-- filter by job type-->
|
|
86
|
-
<div class="input-group input-group-sm mb-1">
|
|
87
|
-
<span class="input-group-text" style="width:35%">Job Type</span>
|
|
88
|
-
<input id="filter-job-type-input" type="text" class="form-control" placeholder="job type" oninput="filterJobsByColumn(2, this.value)">
|
|
89
|
-
<button id="filter-job-type-clear" class="btn btn-outline-secondary" type="button" title="Clear" onclick="clearFilterJobsByColumn(2, '#filter-job-type-input')">
|
|
90
|
-
<i class="bi bi-x-lg"></i>
|
|
91
|
-
</button>
|
|
92
|
-
</div>
|
|
93
|
-
<!-- filter by dag id -->
|
|
94
|
-
<div class="input-group input-group-sm mb-1">
|
|
95
|
-
<span class="input-group-text" style="width:35%">Dag ID</span>
|
|
96
|
-
<select class="form-select" onchange="filterJobsByColumn(3, this.value);this.blur();">
|
|
97
|
-
<option class="text-dark" value="">all</option>
|
|
98
|
-
{% for dag_id in dag_ids %}
|
|
99
|
-
<option class="text-secondary" value="^{{ dag_id }}$">{{ dag_id }}</option>
|
|
100
|
-
{% endfor %}
|
|
101
|
-
</select>
|
|
102
|
-
</div>
|
|
103
|
-
</div>
|
|
104
|
-
</div>
|
|
105
|
-
<!-- job status table -->
|
|
106
|
-
<div>
|
|
107
|
-
<table id="searchJobsTable" class="display compact table table-bordered table-sm" style="font-size: small">
|
|
108
|
-
<thead>
|
|
109
|
-
<tr>
|
|
110
|
-
<th>Asset Name</th>
|
|
111
|
-
<th>Job ID</th>
|
|
112
|
-
<th>Job Type</th>
|
|
113
|
-
<th>Dag ID</th>
|
|
114
|
-
<th>Status</th>
|
|
115
|
-
<th>Submit Time</th>
|
|
116
|
-
<th>Start Time</th>
|
|
117
|
-
<th>End Time</th>
|
|
118
|
-
<th>Comment</th>
|
|
119
|
-
<th>Tasks</th>
|
|
120
|
-
</tr>
|
|
121
|
-
</thead>
|
|
122
|
-
</table>
|
|
123
|
-
<!-- modal for displaying tasks per job from full jobs table -->
|
|
124
|
-
<div class="modal fade" id="tasks-modal-full" tabindex="-1" aria-labelledby="tasks-modal-full-label" aria-hidden="true">
|
|
125
|
-
<div class="modal-dialog modal-xl">
|
|
126
|
-
<div class="modal-content">
|
|
127
|
-
<div class="modal-header p-2">
|
|
128
|
-
<div class="modal-title fw-bold" id="tasks-modal-full-label" style="font-size: small">
|
|
129
|
-
<span id="modal-title-job-name" class="me-2"></span>
|
|
130
|
-
<span id="modal-title-job-id" class="me-2"></span>
|
|
131
|
-
<span id="modal-title-job-state" class="badge"></span>
|
|
132
|
-
</div>
|
|
133
|
-
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
134
|
-
</div>
|
|
135
|
-
<div class="modal-body p-2">
|
|
136
|
-
<iframe id="tasks-iframe" class="w-100 h-100" src=""></iframe>
|
|
137
|
-
</div>
|
|
138
|
-
</div>
|
|
139
|
-
</div>
|
|
140
|
-
</div>
|
|
141
|
-
</div>
|
|
142
|
-
</div>
|
|
143
|
-
<script>
|
|
144
|
-
// User can filter for jobs by status and submit time, and view results.
|
|
145
|
-
// Full Jobs Table: Loads all jobs using DataTables library. Enables searching across all jobs.
|
|
146
|
-
let tableUrl = new URL("{{ url_for('get_job_status_list') }}");
|
|
147
|
-
$(document).ready(function() {
|
|
148
|
-
const today = moment();
|
|
149
|
-
const twoWeeksAgo = moment().subtract(13, 'days');
|
|
150
|
-
|
|
151
|
-
// initialize daterangepicker for submit date filter
|
|
152
|
-
$('#submit-date-range').daterangepicker({
|
|
153
|
-
startDate: twoWeeksAgo,
|
|
154
|
-
endDate: today,
|
|
155
|
-
minDate: twoWeeksAgo,
|
|
156
|
-
maxDate: today,
|
|
157
|
-
ranges: {
|
|
158
|
-
'Today': [today, today],
|
|
159
|
-
'Last 3 Days': [moment().subtract(2, 'days'), today],
|
|
160
|
-
'Last 7 Days': [moment().subtract(6, 'days'), today],
|
|
161
|
-
'Last 14 Days': [twoWeeksAgo, today],
|
|
162
|
-
}
|
|
163
|
-
}, filterJobsBySubmitTimeRange);
|
|
164
|
-
|
|
165
|
-
// initialize job status table with default values
|
|
166
|
-
const initialParams = {
|
|
167
|
-
// set default submit date range client-side for browser's local time
|
|
168
|
-
execution_date_gte: twoWeeksAgo.startOf('day').toISOString(),
|
|
169
|
-
execution_date_lte: today.endOf('day').toISOString(),
|
|
170
|
-
};
|
|
171
|
-
updateJobStatusTable(initialParams);
|
|
172
|
-
|
|
173
|
-
// tasks modal for full jobs table
|
|
174
|
-
var tasksModal = document.getElementById('tasks-modal-full');
|
|
175
|
-
tasksModal.addEventListener('show.bs.modal', function (event) {
|
|
176
|
-
var sourceData = event.relatedTarget?.dataset;
|
|
177
|
-
updateJobTasksModal(sourceData?.dagId, sourceData?.jobId, sourceData?.jobName, sourceData?.jobState);
|
|
178
|
-
})
|
|
179
|
-
tasksModal.addEventListener('hidden.bs.modal', function (event) {
|
|
180
|
-
updateJobTasksModal(null, null, null, null);
|
|
181
|
-
})
|
|
182
|
-
});
|
|
183
|
-
// FULL JOBS TABLE -----------------------------------------------
|
|
184
|
-
// Helper functions for custom column rendering
|
|
185
|
-
function renderJobStatus(cell, cellData, rowData, rowIndex, colIndex) {
|
|
186
|
-
let customClass = cellData === 'success' ? 'table-success'
|
|
187
|
-
: cellData === 'failed' ? 'table-danger'
|
|
188
|
-
: cellData === 'running' ? 'table-info'
|
|
189
|
-
: cellData === 'queued' ? 'table-secondary'
|
|
190
|
-
: null;
|
|
191
|
-
if (customClass) {
|
|
192
|
-
cell.classList.add(customClass);
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
function renderDatetime(data, type, row) {
|
|
196
|
-
return (type === 'display') ? moment.utc(data).local().format('YYYY-MM-DD h:mm:ss a') : data;
|
|
197
|
-
}
|
|
198
|
-
function renderTasksButton(data, type, row) {
|
|
199
|
-
if (type == 'display') {
|
|
200
|
-
return (`<button type="button" class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#tasks-modal-full" data-dag-id="${row.dag_id}" data-job-id="${data}" data-job-name="${row.name}" data-job-state="${row.job_state}">
|
|
201
|
-
<i class="bi bi-box-arrow-up-right" title="View tasks and logs"></i>
|
|
202
|
-
</button>`);
|
|
203
|
-
}
|
|
204
|
-
return data;
|
|
205
|
-
}
|
|
206
|
-
// Create DataTable for full jobs table
|
|
207
|
-
function createFullJobsTable() {
|
|
208
|
-
$('#searchJobsTable').DataTable({
|
|
209
|
-
ajax: {
|
|
210
|
-
url: tableUrl,
|
|
211
|
-
dataSrc: 'data.job_status_list'
|
|
212
|
-
},
|
|
213
|
-
processing: true,
|
|
214
|
-
columns: [
|
|
215
|
-
{ data: 'name', searchable: true },
|
|
216
|
-
{ data: 'job_id', searchable: true },
|
|
217
|
-
{ data: 'job_type', searchable: true },
|
|
218
|
-
{ data: 'dag_id', searchable: true },
|
|
219
|
-
{ data: 'job_state', searchable: true, createdCell: renderJobStatus },
|
|
220
|
-
{ data: 'submit_time', searchable: false, render: renderDatetime },
|
|
221
|
-
{ data: 'start_time', searchable: false, render: renderDatetime },
|
|
222
|
-
{ data: 'end_time', searchable: false, render: renderDatetime },
|
|
223
|
-
{ data: 'comment', searchable: false, defaultContent: 'None' },
|
|
224
|
-
{ data: 'job_id', searchable: false, render: renderTasksButton },
|
|
225
|
-
],
|
|
226
|
-
initComplete: (settings, json) => updateJobsCount(json),
|
|
227
|
-
// layout options
|
|
228
|
-
pageLength: 25,
|
|
229
|
-
order: [5, 'desc'], // submit time descending
|
|
230
|
-
layout: {
|
|
231
|
-
topStart: null,
|
|
232
|
-
topEnd: null,
|
|
233
|
-
bottomStart: null,
|
|
234
|
-
bottomEnd: null,
|
|
235
|
-
top: [
|
|
236
|
-
'pageLength',
|
|
237
|
-
'info',
|
|
238
|
-
{ paging: { numbers: false } }
|
|
239
|
-
],
|
|
240
|
-
},
|
|
241
|
-
language: {
|
|
242
|
-
info: "_START_ to _END_ of _TOTAL_",
|
|
243
|
-
infoEmpty: "0 to 0 of 0",
|
|
244
|
-
entries: { _: "jobs", 1: "job" },
|
|
245
|
-
paginate: {
|
|
246
|
-
first: '« First',
|
|
247
|
-
previous: '‹ Prev',
|
|
248
|
-
next: 'Next ›',
|
|
249
|
-
last: 'Last »'
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
});
|
|
253
|
-
}
|
|
254
|
-
// Modal for tasks per job from full jobs table
|
|
255
|
-
function updateJobTasksModal(dagId, jobId, jobName, jobState) {
|
|
256
|
-
// Update the modal header with the job id and name
|
|
257
|
-
document.getElementById('modal-title-job-id').textContent = `(${jobId})`;
|
|
258
|
-
document.getElementById('modal-title-job-name').textContent = jobName;
|
|
259
|
-
var modalTitleJobState = document.getElementById('modal-title-job-state');
|
|
260
|
-
modalTitleJobState.textContent = jobState;
|
|
261
|
-
if (jobState) {
|
|
262
|
-
modalTitleJobState.classList.add(
|
|
263
|
-
jobState === 'success' ? 'bg-success'
|
|
264
|
-
: jobState === 'failed' ? 'bg-danger'
|
|
265
|
-
: jobState === 'running' ? 'bg-info'
|
|
266
|
-
: 'bg-secondary'
|
|
267
|
-
);
|
|
268
|
-
} else {
|
|
269
|
-
modalTitleJobState.classList.value = 'badge';
|
|
270
|
-
}
|
|
271
|
-
// Update the iframe src with the job id
|
|
272
|
-
var tasksIframe = document.getElementById('tasks-iframe');
|
|
273
|
-
if (jobId) {
|
|
274
|
-
var url = new URL("{{ url_for('job_tasks_table') }}");
|
|
275
|
-
url.searchParams.append('dag_id', dagId);
|
|
276
|
-
url.searchParams.append('dag_run_id', jobId);
|
|
277
|
-
tasksIframe.src = url;
|
|
278
|
-
} else {
|
|
279
|
-
tasksIframe.src = "";
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
// EVENT HANDLERS ------------------------------------------------
|
|
283
|
-
function updateJobStatusTable(newParams) {
|
|
284
|
-
Object.entries(newParams).forEach(([key, value]) => {
|
|
285
|
-
tableUrl.searchParams.set(key, value);
|
|
286
|
-
});
|
|
287
|
-
if (DataTable.isDataTable('#searchJobsTable')) {
|
|
288
|
-
// load the table with new params and update total entries
|
|
289
|
-
$('#searchJobsTable').DataTable().ajax.url(tableUrl.toString()).load(
|
|
290
|
-
(data) => updateJobsCount(data)
|
|
291
|
-
);
|
|
292
|
-
} else {
|
|
293
|
-
createFullJobsTable();
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
function updateJobsCount(data) {
|
|
297
|
-
// data is the response from the server after ajax call
|
|
298
|
-
$('#total-entries').text(data?.data?.total_entries);
|
|
299
|
-
}
|
|
300
|
-
// Filters
|
|
301
|
-
function filterJobsByColumn(columnIndex, value) {
|
|
302
|
-
if (columnIndex == 3 || columnIndex == 4) {
|
|
303
|
-
//exact match for dag_id and job_state dropdowns
|
|
304
|
-
$('#searchJobsTable').DataTable().columns(columnIndex).search(value.trim(), true, false).draw();
|
|
305
|
-
} else {
|
|
306
|
-
// smart match
|
|
307
|
-
$('#searchJobsTable').DataTable().columns(columnIndex).search(value.trim()).draw();
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
function clearFilterJobsByColumn(columnIndex, inputElementId) {
|
|
311
|
-
$(inputElementId).val('');
|
|
312
|
-
filterJobsByColumn(columnIndex, '');
|
|
313
|
-
}
|
|
314
|
-
function filterJobsBySubmitTimeRange(start, end) {
|
|
315
|
-
// This filter is the only one that sends a new ajax request to the server
|
|
316
|
-
// NOTE: daterangepicker already has 00:00:00.000 and 23:59:59.999 for start and end
|
|
317
|
-
updateJobStatusTable({
|
|
318
|
-
execution_date_gte: start.toISOString(),
|
|
319
|
-
execution_date_lte: end.toISOString(),
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
</script>
|
|
323
|
-
</body>
|
|
324
|
-
</html>
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
7
|
-
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.8.1/font/bootstrap-icons.min.css" rel="stylesheet">
|
|
8
|
-
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
9
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.3/moment.min.js"></script>
|
|
10
|
-
</head>
|
|
11
|
-
|
|
12
|
-
<body>
|
|
13
|
-
<!-- tasks table -->
|
|
14
|
-
<table class="table table-bordered table-striped table-hover table-sm" style="font-size: small">
|
|
15
|
-
<tr>
|
|
16
|
-
<th>Task ID</th>
|
|
17
|
-
<th>Try Number</th>
|
|
18
|
-
<th>Map Index</th>
|
|
19
|
-
<th>Status</th>
|
|
20
|
-
<th>Submit Time</th>
|
|
21
|
-
<th>Start Time</th>
|
|
22
|
-
<th>End Time</th>
|
|
23
|
-
<th>Duration</th>
|
|
24
|
-
<th>Logs</th>
|
|
25
|
-
</tr>
|
|
26
|
-
{% for job_task in job_tasks_list %}
|
|
27
|
-
<tr>
|
|
28
|
-
<td>{{job_task.task_id}}</td>
|
|
29
|
-
<td>{{job_task.try_number}}</td>
|
|
30
|
-
<td>
|
|
31
|
-
{% if job_task.map_index > -1 %}
|
|
32
|
-
<span>{{job_task.map_index}}</span>
|
|
33
|
-
{% else %}
|
|
34
|
-
<span></span>
|
|
35
|
-
{% endif %}
|
|
36
|
-
</td>
|
|
37
|
-
<td class="{% if job_task.task_state == 'success' %}table-success
|
|
38
|
-
{% elif job_task.task_state == 'failed' %}table-danger
|
|
39
|
-
{% elif job_task.task_state == 'running' %}table-info
|
|
40
|
-
{% elif job_task.task_state == 'queued' %}table-secondary
|
|
41
|
-
{% endif %}">{{job_task.task_state}}</td>
|
|
42
|
-
<td class="datetime_to_be_adjusted">{{job_task.submit_time}}</td>
|
|
43
|
-
<td class="datetime_to_be_adjusted">{{job_task.start_time}}</td>
|
|
44
|
-
<td class="datetime_to_be_adjusted">{{job_task.end_time}}</td>
|
|
45
|
-
<td>{{job_task.duration}}</td>
|
|
46
|
-
<td>
|
|
47
|
-
{% if job_task.try_number > 0 %}
|
|
48
|
-
<button type="button" class="btn btn-outline-primary btn-sm" data-bs-toggle="modal" data-bs-target="#logs-modal"
|
|
49
|
-
data-dag-id="{{ job_task.dag_id }}"
|
|
50
|
-
data-job-id="{{ job_task.job_id }}"
|
|
51
|
-
data-task-id="{{ job_task.task_id }}"
|
|
52
|
-
data-task-state="{{ job_task.task_state }}"
|
|
53
|
-
data-task-try-number="{{ job_task.try_number }}"
|
|
54
|
-
data-task-map-index="{{ job_task.map_index }}"
|
|
55
|
-
><i class="bi bi-box-arrow-up-right" title="View logs"></i>
|
|
56
|
-
</button>
|
|
57
|
-
{% endif %}
|
|
58
|
-
</td>
|
|
59
|
-
</tr>
|
|
60
|
-
{% endfor %}
|
|
61
|
-
</table>
|
|
62
|
-
<!-- modal for displaying logs per task -->
|
|
63
|
-
<div class="modal fade" id="logs-modal" tabindex="-1" aria-labelledby="logs-modal-label" aria-hidden="true">
|
|
64
|
-
<div class="modal-dialog modal-fullscreen">
|
|
65
|
-
<div class="modal-content">
|
|
66
|
-
<div class="modal-header p-2">
|
|
67
|
-
<div class="modal-title fw-bold" id="logs-modal-label" style="font-size: small">
|
|
68
|
-
<span id="modal-title-task" class="me-2"></span><span id="modal-title-task-state" class="badge"></span>
|
|
69
|
-
</div>
|
|
70
|
-
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
71
|
-
</div>
|
|
72
|
-
<div class="modal-body p-2">
|
|
73
|
-
<iframe id="logs-iframe" class="w-100 h-100" src=""></iframe>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
<!-- display errors to user -->
|
|
79
|
-
{% if status_code != 200 %}
|
|
80
|
-
<div class="alert alert-danger" role="alert">
|
|
81
|
-
<h4 class="alert-heading">{{ message }}</h4>
|
|
82
|
-
<p>
|
|
83
|
-
{% for error in errors %}
|
|
84
|
-
{% if error is string %}{{ error }}
|
|
85
|
-
{% elif error is mapping %}
|
|
86
|
-
{% for key, value in error.items() %}
|
|
87
|
-
<strong>{{ key }}:</strong> {{ value }}<br>
|
|
88
|
-
{% endfor %}
|
|
89
|
-
{% endif %}
|
|
90
|
-
{% endfor %}
|
|
91
|
-
</p>
|
|
92
|
-
</div>
|
|
93
|
-
{% endif %}
|
|
94
|
-
<script>
|
|
95
|
-
window.onload = function () {
|
|
96
|
-
document.querySelectorAll(".datetime_to_be_adjusted").forEach(function (el) {
|
|
97
|
-
if (el.innerHTML !== "") {
|
|
98
|
-
var utcTime = moment.utc(el.innerText); // This is the time in UTC
|
|
99
|
-
utcTime.local(); // Switch to using the browser's local timezone
|
|
100
|
-
el.innerText = utcTime.format('YYYY-MM-DD h:mm:ss a'); // Write the local time back to the element
|
|
101
|
-
};
|
|
102
|
-
});
|
|
103
|
-
var logsModal = document.getElementById('logs-modal');
|
|
104
|
-
logsModal.addEventListener('show.bs.modal', function (event) {
|
|
105
|
-
var sourceData = event.relatedTarget?.dataset;
|
|
106
|
-
updateTaskLogsModal(sourceData?.dagId,sourceData?.jobId, sourceData?.taskId, sourceData?.taskState, sourceData?.taskTryNumber, sourceData?.taskMapIndex);
|
|
107
|
-
})
|
|
108
|
-
logsModal.addEventListener('hidden.bs.modal', function (event) {
|
|
109
|
-
updateTaskLogsModal(null, null, null, null, null, null);
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
function updateTaskLogsModal(dagId, jobId, taskId, taskState, taskTryNumber, taskMapIndex) {
|
|
113
|
-
console.log('updateTaskLogsModal', dagId, jobId, taskId, taskState, taskTryNumber, taskMapIndex);
|
|
114
|
-
// Update the modal header with the task id, try number, map index, and state
|
|
115
|
-
var tryMapLabel = taskMapIndex > -1 ? `${taskId} (try ${taskTryNumber}, map_index ${taskMapIndex})` : `${taskId} (try ${taskTryNumber})`;
|
|
116
|
-
document.getElementById('modal-title-task').textContent = tryMapLabel;
|
|
117
|
-
var modalTitleTaskState = document.getElementById('modal-title-task-state');
|
|
118
|
-
modalTitleTaskState.textContent = taskState;
|
|
119
|
-
if (taskState) {
|
|
120
|
-
modalTitleTaskState.classList.add(
|
|
121
|
-
taskState === 'success' ? 'bg-success'
|
|
122
|
-
: taskState === 'failed' ? 'bg-danger'
|
|
123
|
-
: taskState === 'running' ? 'bg-info'
|
|
124
|
-
: 'bg-secondary'
|
|
125
|
-
);
|
|
126
|
-
} else {
|
|
127
|
-
modalTitleTaskState.classList.value = 'badge';
|
|
128
|
-
}
|
|
129
|
-
// Update the iframe src to get the logs for the task
|
|
130
|
-
var logsIframe = document.getElementById('logs-iframe');
|
|
131
|
-
if (jobId) {
|
|
132
|
-
var url = new URL("{{ url_for('task_logs') }}");
|
|
133
|
-
url.searchParams.append('dag_id', dagId);
|
|
134
|
-
url.searchParams.append('dag_run_id', jobId);
|
|
135
|
-
url.searchParams.append('task_id', taskId);
|
|
136
|
-
url.searchParams.append('try_number', taskTryNumber);
|
|
137
|
-
url.searchParams.append('map_index', taskMapIndex);
|
|
138
|
-
logsIframe.src = url;
|
|
139
|
-
} else {
|
|
140
|
-
logsIframe.src = "";
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
</script>
|
|
144
|
-
</body>
|
|
145
|
-
|
|
146
|
-
</html>
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
6
|
-
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
7
|
-
</head>
|
|
8
|
-
<body>
|
|
9
|
-
{% if status_code == 200 %}
|
|
10
|
-
<!-- display task logs -->
|
|
11
|
-
<div>
|
|
12
|
-
<pre class="bg-light p-1 border rounded" style="font-size: x-small">{{logs}}</pre>
|
|
13
|
-
</div>
|
|
14
|
-
{% else %}
|
|
15
|
-
<!-- display errors to user -->
|
|
16
|
-
<div class="alert alert-danger" role="alert">
|
|
17
|
-
<h4 class="alert-heading">{{ message }}</h4>
|
|
18
|
-
<p>
|
|
19
|
-
{% for error in errors %}
|
|
20
|
-
{% if error is string %}{{ error }}
|
|
21
|
-
{% elif error is mapping %}
|
|
22
|
-
{% for key, value in error.items() %}
|
|
23
|
-
<strong>{{ key }}:</strong> {{ value }}<br>
|
|
24
|
-
{% endfor %}
|
|
25
|
-
{% endif %}
|
|
26
|
-
{% endfor %}
|
|
27
|
-
</p>
|
|
28
|
-
</div>
|
|
29
|
-
{% endif %}
|
|
30
|
-
</body>
|
|
31
|
-
</html>
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
aind_data_transfer_service/__init__.py,sha256=3zeB4HVxFXx2bXdNaQXcSZw0Irq7ZulbJJ5bI0ixIYo,272
|
|
2
|
-
aind_data_transfer_service/log_handler.py,sha256=c7a-gLmZeRpeCUBwCz6XsTszWXQeQdR7eKZtas4llXM,1700
|
|
3
|
-
aind_data_transfer_service/server.py,sha256=1vtmqMKF_7mv2FWrRktvjPmi-slYwt4pfUy51P3WRVc,48341
|
|
4
|
-
aind_data_transfer_service/configs/__init__.py,sha256=9W5GTuso9Is1B9X16RXcdb_GxasZvj6qDzOBDv0AbTc,36
|
|
5
|
-
aind_data_transfer_service/configs/csv_handler.py,sha256=hCdfAYZW_49-l1rbua5On2Tw2ks674Z-MgB_NJlIkU4,5746
|
|
6
|
-
aind_data_transfer_service/configs/job_configs.py,sha256=T-h5N6lyY9xTZ_xg_5FxkyYuMdagApbE6xalxFQ-bqA,18848
|
|
7
|
-
aind_data_transfer_service/configs/job_upload_template.py,sha256=aC5m1uD_YcpbggFQ-yZ7ZJSUUGX1yQqQLF3SwmljrLk,5127
|
|
8
|
-
aind_data_transfer_service/hpc/__init__.py,sha256=YNc68YNlmXwKIPFMIViz_K4XzVVHkLPEBOFyO5DKMKI,53
|
|
9
|
-
aind_data_transfer_service/hpc/client.py,sha256=-JSxAWn96_XOIDwhsXAHK3TZAdckddUhtcCzRHnaTqA,4700
|
|
10
|
-
aind_data_transfer_service/hpc/models.py,sha256=-7HhV16s_MUyKPy0x0FGIbnq8DPL2qJAzJO5G7003AE,16184
|
|
11
|
-
aind_data_transfer_service/models/__init__.py,sha256=Meym73bEZ9nQr4QoeyhQmV3nRTYtd_4kWKPNygsBfJg,25
|
|
12
|
-
aind_data_transfer_service/models/core.py,sha256=uXtPUqjxKalg-sE8MxaJr11w_T_KKBRBSJuUgwoMZlQ,10135
|
|
13
|
-
aind_data_transfer_service/models/internal.py,sha256=tWO1yRMu9hHLv0mt7QhOwTPWGbKApWmCf1wwajx5qjI,10681
|
|
14
|
-
aind_data_transfer_service/templates/admin.html,sha256=owmWgcTFzfWh5S2L82OT-0r5pOt1bl8Fh-C0zyVo1wU,1682
|
|
15
|
-
aind_data_transfer_service/templates/index.html,sha256=TDmmHlhWFPnQrk6nk1OhNjC3SapZtX0TXeuUonoCO7g,11326
|
|
16
|
-
aind_data_transfer_service/templates/job_params.html,sha256=Q5oAsuQqBiTvOOS_7BejcqPJ4rskg_ZtG1E0NAjcGJw,21063
|
|
17
|
-
aind_data_transfer_service/templates/job_status.html,sha256=5lUUGZL-5urppG610qDOgpfIE-OcQH57gFWvRA5pBNM,16938
|
|
18
|
-
aind_data_transfer_service/templates/job_tasks_table.html,sha256=rWFukhjZ4dhPyabe372tmi4lbQS2fyELZ7Awbn5Un4g,6181
|
|
19
|
-
aind_data_transfer_service/templates/task_logs.html,sha256=y1GnQft0S50ghPb2xJDjAlefymB9a4zYdMikUFV7Tl4,918
|
|
20
|
-
aind_data_transfer_service-1.17.0.dist-info/licenses/LICENSE,sha256=U0Y7B3gZJHXpjJVLgTQjM8e_c8w4JJpLgGhIdsoFR1Y,1092
|
|
21
|
-
aind_data_transfer_service-1.17.0.dist-info/METADATA,sha256=pBXxvTxzxZRam6dubbJn7oPNQfBClr1TPUvwrPB3W7U,2478
|
|
22
|
-
aind_data_transfer_service-1.17.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
-
aind_data_transfer_service-1.17.0.dist-info/top_level.txt,sha256=XmxH0q27Jholj2-VYh-6WMrh9Lw6kkuCX_fdsj3SaFE,27
|
|
24
|
-
aind_data_transfer_service-1.17.0.dist-info/RECORD,,
|
{aind_data_transfer_service-1.17.0.dist-info → aind_data_transfer_service-1.17.2.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|