diff --git a/frappe/public/js/frappe/file_uploader/FileUploader.vue b/frappe/public/js/frappe/file_uploader/FileUploader.vue index 2420cc1bf5..50040e0a0e 100644 --- a/frappe/public/js/frappe/file_uploader/FileUploader.vue +++ b/frappe/public/js/frappe/file_uploader/FileUploader.vue @@ -284,6 +284,7 @@ const props = defineProps({ max_file_size: null, // 2048 -> 2KB max_number_of_files: null, allowed_file_types: [], // ['image/*', 'video/*', '.jpg', '.gif', '.pdf'], + blocked_file_types: [], // ['image/heic', 'image/tiff'], crop_image_aspect_ratio: null, // 1, 16 / 9, 4 / 3, NaN (free) }), }, @@ -472,6 +473,7 @@ function check_restrictions(file) { let is_correct_type = true; let valid_file_size = true; + let is_unsupported_file_type = check_unsupported_file_type(file); if (allowed_file_types && allowed_file_types.length) { is_correct_type = allowed_file_types.some((type) => { @@ -493,12 +495,22 @@ function check_restrictions(file) { valid_file_size = file.size < max_file_size; } - if (!is_correct_type) { + if (!is_correct_type || is_unsupported_file_type) { console.warn("File skipped because of invalid file type", file); - frappe.show_alert({ - message: __('File "{0}" was skipped because of invalid file type', [file.name]), - indicator: "orange", - }); + if (is_unsupported_file_type) { + frappe.show_alert({ + message: __('File "{0}" was skipped because of unsupported file type "{1}"', [ + file.name, + file.type, + ]), + indicator: "orange", + }); + } else { + frappe.show_alert({ + message: __('File "{0}" was skipped because of invalid file type', [file.name]), + indicator: "orange", + }); + } } if (!valid_file_size) { console.warn("File skipped because of invalid file size", file.size, file); @@ -511,8 +523,22 @@ function check_restrictions(file) { }); } - return is_correct_type && valid_file_size; + return is_correct_type && valid_file_size && !is_unsupported_file_type; } + +function check_unsupported_file_type(file) { + let { blocked_file_types = [] } = props.restrictions; + return blocked_file_types.some((type) => { + if (type.includes("/")) { + if (!file.type) return false; + return file.type.match(type); + } + if (type[0] === ".") { + return file.name.toLowerCase().endsWith(type.toLowerCase()); + } + }); +} + function upload_files(dialog) { if (show_file_browser.value) { return upload_via_file_browser(); diff --git a/frappe/public/js/frappe/form/controls/attach.js b/frappe/public/js/frappe/form/controls/attach.js index b7fb99072e..7855f667bc 100644 --- a/frappe/public/js/frappe/form/controls/attach.js +++ b/frappe/public/js/frappe/form/controls/attach.js @@ -65,6 +65,13 @@ frappe.ui.form.ControlAttach = class ControlAttach extends frappe.ui.form.Contro on_attach_doc_image() { this.set_upload_options(); this.upload_options.restrictions.allowed_file_types = ["image/*"]; + // file types like .heic/.tiff are not supported for preview directly in the browser, so we block the user from uploading them + this.upload_options.restrictions.blocked_file_types = [ + "image/heic", + "image/heif", + "image/tiff", + "image/tif", + ]; this.file_uploader = new frappe.ui.FileUploader(this.upload_options); } set_upload_options() { diff --git a/frappe/public/js/frappe/form/controls/attach_image.js b/frappe/public/js/frappe/form/controls/attach_image.js index 1fd548f493..91b957afe9 100644 --- a/frappe/public/js/frappe/form/controls/attach_image.js +++ b/frappe/public/js/frappe/form/controls/attach_image.js @@ -21,5 +21,12 @@ frappe.ui.form.ControlAttachImage = class ControlAttachImage extends frappe.ui.f set_upload_options() { super.set_upload_options(); this.upload_options.restrictions.allowed_file_types = ["image/*"]; + // file types like .heic/.tiff are not supported for preview directly in the browser, so we block the user from uploading them + this.upload_options.restrictions.blocked_file_types = [ + "image/heic", + "image/heif", + "image/tiff", + "image/tif", + ]; } };