Merge pull request #15003 from mituldavid/file-uploader

refactor: Display errors in FilePreview
This commit is contained in:
mergify[bot] 2021-11-23 06:19:38 +00:00 committed by GitHub
commit e94ce5c8a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 66 additions and 21 deletions

View file

@ -120,6 +120,8 @@ def init_request(request):
else:
frappe.connect(set_admin_as_user=False)
request.max_content_length = frappe.local.conf.get('max_file_size') or 10 * 1024 * 1024
make_form_dict(request)
if request.method != "OPTIONS":

View file

@ -716,13 +716,11 @@ def delete_file(path):
os.remove(path)
@frappe.whitelist()
def get_max_file_size():
return cint(conf.get('max_file_size')) or 10485760
def has_permission(doc, ptype=None, user=None):
has_access = False
user = user or frappe.session.user

View file

@ -29,21 +29,26 @@
</span>
</div>
<label v-if="is_optimizable" class="optimize-checkbox"><input type="checkbox" :checked="optimize" @change="$emit('toggle_optimize')">Optimize</label>
<div>
<span v-if="file.error_message" class="file-error text-danger">
{{ file.error_message }}
</span>
</div>
</div>
<div class="file-actions">
<ProgressRing
v-show="file.uploading && !uploaded"
v-show="file.uploading && !uploaded && !file.failed"
primary="var(--primary-color)"
secondary="var(--gray-200)"
radius="24"
:radius="24"
:progress="progress"
stroke="3"
:stroke="3"
/>
<div v-if="uploaded" v-html="frappe.utils.icon('solid-success', 'lg')"></div>
<div v-if="file.failed" v-html="frappe.utils.icon('solid-red', 'lg')"></div>
<div v-if="file.failed" v-html="frappe.utils.icon('solid-error', 'lg')"></div>
<div class="file-action-buttons">
<button v-if="is_cropable" class="btn btn-crop muted" @click="$emit('toggle_image_cropper')" v-html="frappe.utils.icon('crop', 'md')"></button>
<button v-if="!uploaded && !file.uploading" class="btn muted" @click="$emit('remove')" v-html="frappe.utils.icon('delete', 'md')"></button>
<button v-if="!uploaded && !file.uploading && !file.failed" class="btn muted" @click="$emit('remove')" v-html="frappe.utils.icon('delete', 'md')"></button>
</div>
</div>
</div>
@ -89,18 +94,18 @@ export default {
return this.file.doc ? this.file.doc.is_private : this.file.private;
},
uploaded() {
return this.file.total && this.file.total === this.file.progress && !this.file.failed;
return this.file.request_succeeded;
},
is_image() {
return this.file.file_obj.type.startsWith('image');
},
is_optimizable() {
let is_svg = this.file.file_obj.type == 'image/svg+xml';
return this.is_image && !is_svg;
return this.is_image && !is_svg && !this.uploaded && !this.file.failed;
},
is_cropable() {
let croppable_types = ['image/jpeg', 'image/png'];
return !this.uploaded && !this.file.uploading && croppable_types.includes(this.file.file_obj.type);
return !this.uploaded && !this.file.uploading && !this.file.failed && croppable_types.includes(this.file.file_obj.type);
},
progress() {
let value = Math.round((this.file.progress * 100) / this.file.total);
@ -208,4 +213,9 @@ export default {
align-items: center;
padding-top: 0.25rem;
}
.file-error {
font-size: var(--text-sm);
font-weight: var(--text-bold);
}
</style>

View file

@ -197,6 +197,7 @@ export default {
show_image_cropper: false,
crop_image_with_index: -1,
trigger_upload: false,
close_dialog: false,
hide_dialog_footer: false,
allow_take_photo: false,
allow_web_link: true,
@ -218,6 +219,12 @@ export default {
}
});
}
if (this.restrictions.max_file_size == null) {
frappe.call('frappe.core.doctype.file.file.get_max_file_size')
.then(res => {
this.restrictions.max_file_size = Number(res.message);
});
}
},
watch: {
files(newvalue, oldvalue) {
@ -289,6 +296,8 @@ export default {
progress: 0,
total: 0,
failed: false,
request_succeeded: false,
error_message: null,
uploading: false,
private: !is_image
}
@ -329,9 +338,17 @@ export default {
if (!is_correct_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 (!valid_file_size) {
console.warn('File skipped because of invalid file size', file.size, file);
frappe.show_alert({
message: __('File "{0}" was skipped because size exceeds {1} MB', [file.name, max_file_size / (1024 * 1024)]),
indicator: 'orange'
});
}
return is_correct_type && valid_file_size;
@ -357,9 +374,10 @@ export default {
let selected_file = this.$refs.file_browser.selected_node;
if (!selected_file.value) {
frappe.msgprint(__('Click on a file to select it.'));
this.close_dialog = true;
return Promise.reject();
}
this.close_dialog = true;
return this.upload_file({
file_url: selected_file.file_url
});
@ -368,9 +386,11 @@ export default {
let file_url = this.$refs.web_link.url;
if (!file_url) {
frappe.msgprint(__('Invalid URL'));
this.close_dialog = true;
return Promise.reject();
}
file_url = decodeURI(file_url)
this.close_dialog = true;
return this.upload_file({
file_url
});
@ -383,6 +403,7 @@ export default {
this.on_success && this.on_success(file);
})
);
this.close_dialog = true;
return Promise.all(promises);
},
upload_file(file, i) {
@ -410,6 +431,7 @@ export default {
xhr.onreadystatechange = () => {
if (xhr.readyState == XMLHttpRequest.DONE) {
if (xhr.status === 200) {
file.request_succeeded = true;
let r = null;
let file_doc = null;
try {
@ -426,15 +448,24 @@ export default {
if (this.on_success) {
this.on_success(file_doc, r);
}
if (i == this.files.length - 1 && this.files.every(file => file.request_succeeded)) {
this.close_dialog = true;
}
} else if (xhr.status === 403) {
file.failed = true;
let response = JSON.parse(xhr.responseText);
frappe.msgprint({
title: __('Not permitted'),
indicator: 'red',
message: response._error_message
});
file.error_message = `Not permitted. ${response._error_message || ''}`;
} else if (xhr.status === 413) {
file.failed = true;
file.error_message = 'Size exceeds the maximum allowed file size.';
} else {
file.failed = true;
file.error_message = xhr.status === 0 ? 'XMLHttpRequest Error' : `${xhr.status} : ${xhr.statusText}`;
let error = null;
try {
error = JSON.parse(xhr.responseText);

View file

@ -67,6 +67,12 @@ export default class FileUploader {
}
});
this.uploader.$watch('close_dialog', (close_dialog) => {
if (close_dialog) {
this.dialog && this.dialog.hide();
}
});
this.uploader.$watch('hide_dialog_footer', (hide_dialog_footer) => {
if (hide_dialog_footer) {
this.dialog && this.dialog.footer.addClass('hide');
@ -84,10 +90,8 @@ export default class FileUploader {
upload_files() {
this.dialog && this.dialog.get_primary_btn().prop('disabled', true);
return this.uploader.upload_files()
.then(() => {
this.dialog && this.dialog.hide();
});
this.dialog && this.dialog.get_secondary_btn().prop('disabled', true);
return this.uploader.upload_files();
}
make_dialog() {