Skip to content

Commit ce82879

Browse files
author
dajtxx
committed
Added a spinner to show the data download is happening.
1 parent ad745db commit ce82879

File tree

1 file changed

+90
-37
lines changed

1 file changed

+90
-37
lines changed

src/www/app/templates/logical_device_form.html

+90-37
Original file line numberDiff line numberDiff line change
@@ -13,39 +13,61 @@
1313
right: 16px;
1414
width: 100%;
1515
text-align: right;
16-
}
16+
}
17+
18+
#loading-spinner {
19+
position: fixed;
20+
top: 0;
21+
left: 0;
22+
width: 100%;
23+
height: 100%;
24+
background-color: rgba(0, 0, 0, 0.5); /* semi-transparent background */
25+
z-index: 9999; /* high z-index to ensure it's on top */
26+
display: flex;
27+
justify-content: center;
28+
align-items: center;
29+
}
30+
31+
.spinner {
32+
border: 4px solid #f3f3f3;
33+
border-top: 4px solid #3498db;
34+
border-radius: 50%;
35+
width: 40px;
36+
height: 40px;
37+
animation: spin 1s linear infinite;
38+
}
39+
40+
@keyframes spin {
41+
0% { transform: rotate(0deg); }
42+
100% { transform: rotate(360deg); }
43+
}
1744
</style>
1845

1946
<script type="text/javascript">
2047
let start_ts_inst = null;
2148
let end_ts_inst = null;
2249
let dialog = null;
2350

24-
$(document).ready(function () {
25-
dialog = document.getElementById('export-data');
26-
// A submit handler would avoid this getting called when the dialog is dismissed using
27-
// the escape key, but it does not get the correct value for dialog.returnValue.
28-
//
29-
// The close handler gets called all the time but at least dialog.returnValue has a
30-
// valid value.
31-
dialog.addEventListener("close", function(event) {
32-
console.log($("#start_ts").val());
33-
console.log($("#end_ts").val());
34-
console.log(dialog.returnValue);
51+
async function doFetch(event) {
52+
console.log($("#start_ts").val());
53+
console.log($("#end_ts").val());
54+
console.log(dialog.returnValue);
3555

36-
if (start_ts_inst) {
37-
start_ts_inst.destroy();
38-
}
39-
if (end_ts_inst) {
40-
end_ts_inst.destroy();
41-
}
56+
if (start_ts_inst) {
57+
start_ts_inst.destroy();
58+
}
59+
if (end_ts_inst) {
60+
end_ts_inst.destroy();
61+
}
4262

43-
if ('Export'.localeCompare(dialog.returnValue) === 0) {
63+
if ('Export'.localeCompare(dialog.returnValue) === 0) {
64+
try {
65+
showSpinner();
4466
console.log('Exporting data');
4567
const formElement = document.getElementById('single-ld-export');
4668
const formData = new FormData(formElement);
4769
console.log(formData);
48-
fetch(formElement.action, {
70+
x = fetch(formElement.action, {
4971
method: 'POST',
5072
body: formData
5173
})
@@ -55,38 +77,54 @@
5577
}
5678
const blob = await response.blob();
5779
const filename = response.headers.get('Content-Disposition')?.split('filename=')[1]?.replace(/['"]/g, '') || 'download.csv';
58-
80+
5981
// Check if the showSaveFilePicker API is available
6082
if ('showSaveFilePicker' in window) {
61-
try {
83+
try {
6284
const handle = await window.showSaveFilePicker({
63-
suggestedName: filename,
64-
types: [{
85+
suggestedName: filename,
86+
types: [{
6587
description: 'CSV File',
6688
accept: {'text/csv': ['.csv']},
67-
}],
89+
}],
6890
});
6991
const writable = await handle.createWritable();
7092
await writable.write(blob);
7193
await writable.close();
72-
} catch (err) {
94+
} catch (err) {
7395
if (err.name !== 'AbortError') {
74-
console.error('Failed to save file:', err);
75-
// Fallback to the older method
76-
saveBlobAsFile(blob, filename);
96+
console.error('Failed to save file:', err);
97+
// Fallback to the older method
98+
saveBlobAsFile(blob, filename);
7799
}
78-
}
100+
}
79101
} else {
80-
// Fallback for browsers that don't support showSaveFilePicker
81-
saveBlobAsFile(blob, filename);
102+
// Fallback for browsers that don't support showSaveFilePicker
103+
saveBlobAsFile(blob, filename);
82104
}
83105
})
84106
.catch(error => {
85107
console.error('Error:', error);
108+
// Does this show up when the spinnder is active?
86109
alert("Error occured on submission", error);
87110
});
111+
112+
// Wait for the fetch to finish so the spinner shows up.
113+
await x;
114+
} finally {
115+
hideSpinner();
88116
}
89-
});
117+
}
118+
}
119+
120+
$(document).ready(function () {
121+
dialog = document.getElementById('export-data');
122+
// A submit handler would avoid this getting called when the dialog is dismissed using
123+
// the escape key, but it does not get the correct value for dialog.returnValue.
124+
//
125+
// The close handler gets called all the time but at least dialog.returnValue has a
126+
// valid value.
127+
dialog.addEventListener("close", doFetch);
90128
});
91129

92130
function exportData(l_uid, name) {
@@ -121,9 +159,24 @@
121159
a.click();
122160
window.URL.revokeObjectURL(url);
123161
document.body.removeChild(a);
124-
}
162+
}
163+
164+
function showSpinner() {
165+
console.log('showing spinner');
166+
document.getElementById('loading-spinner').style.display = 'flex';
167+
}
168+
169+
function hideSpinner() {
170+
console.log('hiding spinner');
171+
document.getElementById('loading-spinner').style.display = 'none';
172+
}
125173
</script>
126174

175+
<!-- Are the nested divs necessary or is the inner one sufficient? -->
176+
<div id="loading-spinner" style="display: none;">
177+
<div class="spinner"></div>
178+
</div>
179+
127180
<dialog id="export-data">
128181
<header>
129182
<h3 style="padding: 8px">Export data</h3>
@@ -157,8 +210,8 @@ <h3 style="padding: 8px">Export data</h3>
157210
<li><span class="btn" onclick="handleMapping('logical device')">Update Mapping</span></li>
158211
<li><span class="btn" onclick="handleEndMapping('{{ ld_data.uid }}', 'LD')">End Mapping</span></li>
159212
{% if deviceMappings | length > 0 %}
160-
<li><span class="btn" onclick="handleToggleMapping('{{ deviceMappings[0].pd.uid }}','{{ deviceMappings[0].is_active }}', 'PD')">{{ "Pause Mapping" if deviceMappings[0].is_active == True else "Resume Mapping" }}</span></li>
161-
{% endif %}
213+
<li><span class="btn" onclick="handleToggleMapping('{{ deviceMappings[0].pd.uid }}','{{ deviceMappings[0].is_active }}', 'PD')">{{ "Pause Mapping" if deviceMappings[0].is_active == True else "Resume Mapping" }}</span></li>
214+
{% endif %}
162215
</ul>
163216
</div>
164217
</div>
@@ -262,4 +315,4 @@ <h3 id="mapping-heading">Mapping</h3>
262315
</div>
263316
</section>
264317

265-
{% endblock %}
318+
{% endblock %}

0 commit comments

Comments
 (0)