Skip to content

Commit edebbee

Browse files
committed
feat: Display upload errors in UIWindowProgress dialog
The object returned from UIWindowProgress() now has a `show_error()` method, taking a title and message. Calling it will replace the content of the window with those messages. I've made use of this for file uploads. The only other place we currently have errors we could show is for zipping and downloading files, but we do not always have a progress dialog in that case, so I'll leave that for now. I think ideally, we would always create a progress dialog, and it would then support being invisible initially, but appearing after a delay. Then we'd always have an object to call `show_error()` on, and it could then immediately show the dialog. But I'll get to that another day. :^)
1 parent f326969 commit edebbee

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

src/UI/UIWindowProgress.js

+49-19
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ import Button from './Components/Button.js';
2626
* @param operation_id If provided, is saved in the data-operation-id attribute, for later lookup.
2727
* @param show_progress Enable a progress bar, and display `(foo%)` after the status message
2828
* @param on_cancel A callback run when the Cancel button is clicked. Without it, no Cancel button will appear.
29-
* @returns {Promise<{set_progress: *, set_status: *, close: *, element: Element}>} Object for managing the progress dialog
29+
* @returns {Promise<{set_progress: *, set_status: *, close: *, show_error: *, element: Element}>} Object for managing the progress dialog
3030
* @constructor
31-
* TODO: Error display
3231
* TODO: Debouncing logic (show only after a delay, then hide only after a delay)
3332
*/
3433
async function UIWindowProgress({
@@ -37,30 +36,47 @@ async function UIWindowProgress({
3736
on_cancel = null,
3837
} = {}){
3938
const placeholder_cancel_btn = Placeholder();
39+
const placeholder_ok_btn = Placeholder();
4040

4141
let h = '';
4242
h += `<div ${operation_id ? `data-operation-id="${operation_id}"` : ''}>`;
43-
h += `<div style="display: flex; align-items: center;">`;
44-
// spinner
45-
h += `<svg style="margin-right: 7px; overflow: visible;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
46-
// Progress report
47-
h += `<div style="font-size:15px; overflow: hidden; flex-grow: 1; text-overflow: ellipsis; white-space: nowrap;">
48-
<span class="progress-msg">${i18n('preparing')}</span>`;
43+
h += `<div class="progress-running">`;
44+
h += `<div style="display: flex; align-items: center; gap: 7px;">`;
45+
// spinner
46+
h += `<svg style="overflow: visible;" xmlns="http://www.w3.org/2000/svg" height="24" width="24" viewBox="0 0 24 24"><title>circle anim</title><g fill="#212121" class="nc-icon-wrapper"><g class="nc-loop-circle-24-icon-f"><path d="M12 24a12 12 0 1 1 12-12 12.013 12.013 0 0 1-12 12zm0-22a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2z" fill="#212121" opacity=".4"></path><path d="M24 12h-2A10.011 10.011 0 0 0 12 2V0a12.013 12.013 0 0 1 12 12z" data-color="color-2"></path></g><style>.nc-loop-circle-24-icon-f{--animation-duration:0.5s;transform-origin:12px 12px;animation:nc-loop-circle-anim var(--animation-duration) infinite linear}@keyframes nc-loop-circle-anim{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}</style></g></svg>`;
47+
// Progress report
48+
h += `<div style="font-size:15px; overflow: hidden; flex-grow: 1; text-overflow: ellipsis; white-space: nowrap;">
49+
<span class="progress-msg">${i18n('preparing')}</span>`;
50+
if (show_progress) {
51+
h += ` (<span class="progress-percent">0%</span>)`;
52+
}
53+
h += `</div>`;
54+
h +=`</div>`;
4955
if (show_progress) {
50-
h += ` (<span class="progress-percent">0%</span>)`;
56+
h += `<div class="progress-bar-container" style="margin-top:20px;">`;
57+
h += `<div class="progress-bar"></div>`;
58+
h += `</div>`;
5159
}
60+
if (on_cancel) {
61+
h += `<div style="display: flex; justify-content: flex-end;">`;
62+
h += placeholder_cancel_btn.html;
63+
h += `</div>`;
64+
}
65+
h += `</div>`;
66+
h += `<div class="progress-error" style="display: none">`;
67+
h += `<div style="display: flex; align-items: center; gap: 7px;">`;
68+
// Alert icon
69+
h += `<img style="width:24px; height:24px;" src="${html_encode(window.icons['warning-sign.svg'])}" />`;
70+
// Progress report
71+
h += `<div style="font-size:15px; overflow: hidden; flex-grow: 1; text-overflow: ellipsis; white-space: nowrap;">
72+
<span class="progress-error-title"></span>`;
73+
h += `</div>`;
5274
h += `</div>`;
53-
h +=`</div>`;
54-
if (show_progress) {
55-
h += `<div class="progress-bar-container" style="margin-top:20px;">`;
56-
h += `<div class="progress-bar"></div>`;
57-
h += `</div>`;
58-
}
59-
if (on_cancel) {
75+
h += `<p class="progress-error-message"></p>`;
6076
h += `<div style="display: flex; justify-content: flex-end;">`;
61-
h += placeholder_cancel_btn.html;
77+
h += placeholder_ok_btn.html;
6278
h += `</div>`;
63-
}
79+
h += `</div>`;
6480
h += `</div>`;
6581

6682
const el_window = await UIWindow({
@@ -106,6 +122,15 @@ async function UIWindowProgress({
106122
cancel_btn.attach(placeholder_cancel_btn);
107123
}
108124

125+
const ok_btn = new Button({
126+
label: i18n('ok'),
127+
style: 'small',
128+
on_click: () => {
129+
$(el_window).close();
130+
},
131+
});
132+
ok_btn.attach(placeholder_ok_btn);
133+
109134
return {
110135
element: el_window,
111136
set_status: (text) => {
@@ -118,7 +143,12 @@ async function UIWindowProgress({
118143
close: () => {
119144
$(el_window).close();
120145
},
121-
// TODO: show_error(), which replaces the window content with a title, error message, and OK button
146+
show_error: (title, message) => {
147+
el_window.querySelector('.progress-running').style.display = 'none';
148+
el_window.querySelector('.progress-error').style.display = 'block';
149+
el_window.querySelector('.progress-error-title').innerText = title;
150+
el_window.querySelector('.progress-error-message').innerText = message;
151+
},
122152
};
123153
}
124154

src/helpers.js

+1-3
Original file line numberDiff line numberDiff line change
@@ -2771,9 +2771,7 @@ window.upload_items = async function(items, dest_path){
27712771
},
27722772
// error
27732773
error: async function(err){
2774-
// TODO: Display error in progress dialog
2775-
upload_progress_window.close();
2776-
// UIAlert(err?.message ?? 'An error occurred while uploading.');
2774+
upload_progress_window.show_error(i18n('error_uploading_files'), err.message);
27772775
// remove from active_uploads
27782776
delete window.active_uploads[opid];
27792777
},

src/i18n/translations/en.js

+1
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ const en = {
114114
enlarged_qr_code: "Enlarged QR Code",
115115
enter_password_to_confirm_delete_user: "Enter your password to confirm account deletion",
116116
error_unknown_cause: "An unknown error occurred.",
117+
error_uploading_files: "Failed to upload files",
117118
feedback: "Feedback",
118119
feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.",
119120
feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.",

0 commit comments

Comments
 (0)