Merge pull request #37112 from TITANiumRox/fix-file-uploader-error-handling

fix: error message dialogs in File Uploader for web link upload
This commit is contained in:
Suraj Shetty 2026-02-21 01:02:41 +05:30 committed by GitHub
commit ee007d839b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 70 additions and 24 deletions

View file

@ -513,25 +513,36 @@ function check_restrictions(file) {
return is_correct_type && valid_file_size;
}
function set_loading_state(dialog, loading) {
let $btn = dialog?.get_primary_btn();
if (loading) {
$btn?.css("width", $btn.outerWidth());
$btn?.html(`<i class="fa fa-spinner fa-spin"></i>`);
$btn?.prop("disabled", true);
dialog?.get_secondary_btn().prop("disabled", true);
} else {
$btn?.css("width", "");
$btn?.html(__("Upload"));
$btn?.prop("disabled", false);
dialog?.get_secondary_btn().prop("disabled", false);
}
}
function upload_files(dialog) {
set_loading_state(dialog, true);
if (show_file_browser.value) {
return upload_via_file_browser();
}
if (show_web_link.value) {
return upload_via_web_link();
}
if (props.as_dataurl) {
return return_as_dataurl();
}
if (!files.value.length) {
promise = upload_via_file_browser();
} else if (show_web_link.value) {
promise = upload_via_web_link();
} else if (props.as_dataurl) {
promise = return_as_dataurl();
} else if (!files.value.length) {
frappe.msgprint(__("Please select a file first."));
return Promise.reject();
promise = Promise.reject();
} else {
promise = frappe.run_serially(files.value.map((file, i) => () => upload_file(file, i)));
}
dialog?.get_primary_btn().prop("disabled", true);
dialog?.get_secondary_btn().prop("disabled", true);
return frappe.run_serially(files.value.map((file, i) => () => upload_file(file, i)));
return promise.finally(() => set_loading_state(dialog, false));
}
function upload_via_file_browser() {
let selected_file = file_browser.value.selected_node;
@ -548,12 +559,16 @@ function upload_via_file_browser() {
function upload_via_web_link() {
let file_url = web_link.value.url;
if (!file_url) {
frappe.msgprint(__("Invalid URL"));
close_dialog.value = true;
web_link.value.invalid_input(__("Please enter a valid URL"));
return Promise.reject();
}
try {
file_url = decodeURI(file_url);
} catch (error) {
var error_message = error.message;
web_link.value.invalid_input(__(error_message));
return Promise.reject();
}
file_url = decodeURI(file_url);
close_dialog.value = true;
return upload_file({
file_url,
});
@ -584,7 +599,6 @@ function upload_file(file, i) {
});
xhr.upload.addEventListener("load", (e) => {
file.uploading = false;
resolve();
});
xhr.addEventListener("error", (e) => {
file.failed = true;
@ -593,6 +607,7 @@ function upload_file(file, i) {
xhr.onreadystatechange = () => {
if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status === 200) {
resolve();
file.request_succeeded = true;
let r = null;
let file_doc = null;
@ -617,7 +632,11 @@ function upload_file(file, i) {
) {
close_dialog.value = true;
}
if (show_web_link.value && file.file_url) {
close_dialog.value = true;
}
} else if (xhr.status === 403) {
reject();
file.failed = true;
let response = parse_error_response(xhr.responseText);
file.error_message = __("Not permitted. {0}.", [response.error_message || ""]);
@ -625,16 +644,29 @@ function upload_file(file, i) {
file.error_message += `\n${response.server_messages.join("\n")}`;
}
} else if (xhr.status === 413) {
reject();
file.failed = true;
file.error_message = __("Size exceeds the maximum allowed file size.");
} else if (xhr.status === 417) {
reject();
// regular frappe.throw() in backend
file.failed = true;
let response = parse_error_response(xhr.responseText);
file.error_message = response.server_messages.length
? response.server_messages.join("\n")
: __("File upload failed.");
if (show_web_link.value && web_link.value && file.file_url) {
web_link.value.invalid_input(__(file.error_message));
} else if (!files.value.includes(file)) {
frappe.msgprint({
title: __("Upload Failed"),
message: __(file.error_message),
indicator: "red",
});
}
} else {
reject();
file.failed = true;
let detail =
xhr.statusText ||

View file

@ -1,28 +1,42 @@
<template>
<div class="file-web-link margin-bottom">
<div class="file-web-link" :style="{ 'margin-bottom': error_message ? '0' : '0.5rem' }">
<a href class="text-muted text-medium" @click.prevent="emit('hide-web-link')">
{{ __("← Back to upload files") }}
</a>
<div class="input-group">
<input
ref="web_link_input"
type="text"
class="form-control"
class="form-control mr-1"
:class="{ 'is-invalid': error_message }"
:placeholder="__('Attach a web link')"
v-model="url"
/>
</div>
<div class="text-small text-danger pt-1" v-if="error_message">{{ error_message }}</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { ref, watch } from "vue";
// emits
let emit = defineEmits(["hide-web-link"]);
let url = ref("");
let web_link_input = ref(null);
let error_message = ref("");
defineExpose({ url });
watch(url, () => {
error_message.value = "";
});
function invalid_input(error) {
error_message.value = error;
web_link_input.value?.focus();
}
defineExpose({ url, invalid_input });
</script>
<style scoped>