From fa241580d91fcd93e5b77378df673ce5ef5658ef Mon Sep 17 00:00:00 2001 From: marination Date: Wed, 26 Jul 2023 19:49:28 +0530 Subject: [PATCH] feat: Sidebar Attachments accessibility - Issue: With a large volume of attachments, the "Attach File" button is pushed to the bottom - "Attach File" stays at the top of the pile - Small explore files button added so that users can use the File View to navigate/filter through files - Expanded Explore Files button when attach file action is hidden - Added `file_type` to Files, this is useful for filtering and visibility - Added "Type" to File List View - Patch to set File Type in all files --- frappe/core/doctype/file/file.js | 3 +- frappe/core/doctype/file/file.json | 16 +++++++- frappe/core/doctype/file/file.py | 11 +++++ frappe/patches.txt | 1 + frappe/patches/v15_0/set_file_type.py | 18 +++++++++ .../js/frappe/form/sidebar/attachments.js | 35 +++++++++++++++- .../frappe/form/templates/form_sidebar.html | 40 ++++++++++++++----- .../public/js/frappe/views/file/file_view.js | 6 +++ frappe/public/scss/desk/sidebar.scss | 12 +++++- 9 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 frappe/patches/v15_0/set_file_type.py diff --git a/frappe/core/doctype/file/file.js b/frappe/core/doctype/file/file.js index 159cf1ce39..f1443d09f5 100644 --- a/frappe/core/doctype/file/file.js +++ b/frappe/core/doctype/file/file.js @@ -24,8 +24,7 @@ frappe.ui.form.on("File", { preview_file: function (frm) { let $preview = ""; - let file_name = frm.doc.file_name.split("?")[0]; - let file_extension = file_name.split(".").pop()?.toLowerCase(); + let file_extension = frm.doc.file_type.toLowerCase(); if (frappe.utils.is_image_file(frm.doc.file_url)) { $preview = $(`
diff --git a/frappe/core/doctype/file/file.json b/frappe/core/doctype/file/file.json index 6c64bfe274..11f80183b7 100644 --- a/frappe/core/doctype/file/file.json +++ b/frappe/core/doctype/file/file.json @@ -8,6 +8,8 @@ "field_order": [ "file_name", "is_private", + "column_break_7jmm", + "file_type", "preview", "preview_html", "section_break_5", @@ -168,13 +170,25 @@ "fieldtype": "Check", "label": "Uploaded To Google Drive", "read_only": 1 + }, + { + "fieldname": "column_break_7jmm", + "fieldtype": "Column Break" + }, + { + "fieldname": "file_type", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "File Type", + "read_only": 1 } ], "force_re_route_to_default_view": 1, "icon": "fa fa-file", "idx": 1, "links": [], - "modified": "2023-05-02 15:42:14.274901", + "modified": "2023-07-26 14:03:49.456951", "modified_by": "Administrator", "module": "Core", "name": "File", diff --git a/frappe/core/doctype/file/file.py b/frappe/core/doctype/file/file.py index cc3c2c228e..1a5bd54f9b 100755 --- a/frappe/core/doctype/file/file.py +++ b/frappe/core/doctype/file/file.py @@ -44,6 +44,7 @@ class File(Document): content_hash: DF.Data | None file_name: DF.Data | None file_size: DF.Int + file_type: DF.Data | None file_url: DF.Code | None folder: DF.Link | None is_attachments_folder: DF.Check @@ -86,6 +87,7 @@ class File(Document): self.set_folder_name() self.set_file_name() self.validate_attachment_limit() + self.set_file_type() if self.is_folder: return @@ -330,6 +332,15 @@ class File(Document): elif not self.is_home_folder: self.folder = "Home" + def set_file_type(self): + if self.is_folder: + return + + file_name = self.file_name.split("?")[0] + file_extension = file_name.split(".")[-1].upper() if file_name.split(".")[-1] else None + if file_extension: + self.file_type = file_extension + def validate_file_on_disk(self): """Validates existence file""" full_path = self.get_full_path() diff --git a/frappe/patches.txt b/frappe/patches.txt index 054fe9b946..45f3a73432 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -227,3 +227,4 @@ execute:frappe.delete_doc_if_exists("Workspace", "Customization") execute:frappe.db.set_single_value("Document Naming Settings", "default_amend_naming", "Amend Counter") execute:frappe.delete_doc_if_exists("DocType", "Error Snapshot") frappe.patches.v15_0.move_event_cancelled_to_status +frappe.patches.v15_0.set_file_type diff --git a/frappe/patches/v15_0/set_file_type.py b/frappe/patches/v15_0/set_file_type.py new file mode 100644 index 0000000000..a46787f491 --- /dev/null +++ b/frappe/patches/v15_0/set_file_type.py @@ -0,0 +1,18 @@ +import frappe + + +def execute(): + """Set 'File Type' for all files based on file extension.""" + files = frappe.db.get_all( + "File", + fields=["name", "file_name", "is_folder"], + ) + + for file in files: + if file.get("is_folder"): + continue + + file_name = file.get("file_name").split("?")[0] + file_extension = file_name.split(".")[-1].upper() if file_name.split(".")[-1] else None + if file_extension: + frappe.db.set_value("File", file.get("name"), "file_type", file_extension) diff --git a/frappe/public/js/frappe/form/sidebar/attachments.js b/frappe/public/js/frappe/form/sidebar/attachments.js index b7763c397d..2c344140c4 100644 --- a/frappe/public/js/frappe/form/sidebar/attachments.js +++ b/frappe/public/js/frappe/form/sidebar/attachments.js @@ -11,7 +11,16 @@ frappe.ui.form.Attachments = class Attachments { this.parent.find(".add-attachment-btn").click(function () { me.new_attachment(); }); - this.add_attachment_wrapper = this.parent.find(".add-attachment-btn"); + + this.parent.find(".explore-btn").click(() => { + frappe.open_in_new_tab = true; + frappe.set_route("List", "File", { + attached_to_doctype: this.frm.doctype, + attached_to_name: this.frm.docname, + }); + }); + + this.add_attachment_wrapper = this.parent.find(".attachments-actions"); this.attachments_label = this.parent.find(".attachments-label"); } max_reached(raise_exception = false) { @@ -42,6 +51,7 @@ frappe.ui.form.Attachments = class Attachments { var max_reached = this.max_reached(); this.add_attachment_wrapper.toggle(!max_reached); + this.setup_expanded_explore_button(max_reached); // add attachment objects var attachments = this.get_attachments(); @@ -57,11 +67,29 @@ frappe.ui.form.Attachments = class Attachments { }); } else { this.attachments_label.removeClass("has-attachments"); + this.parent.find(".explore-btn").toggle(false); // hide explore icon button } } + + setup_expanded_explore_button(max_reached) { + if (!max_reached) { + this.parent.find(".explore-full-btn").addClass("hidden"); + return; + } + + this.parent.find(".explore-full-btn").removeClass("hidden"); + this.parent.find(".explore-full-btn").click(() => { + frappe.set_route("List", "File", { + attached_to_doctype: this.frm.doctype, + attached_to_name: this.frm.docname, + }); + }); + } + get_attachments() { return this.frm.get_docinfo().attachments || []; } + add_attachment(attachment) { var file_name = attachment.file_name; var file_url = this.get_file_url(attachment); @@ -101,8 +129,11 @@ frappe.ui.form.Attachments = class Attachments { $(`
  • `) .append(frappe.get_data_pill(file_label, fileid, remove_action, icon)) - .insertAfter(this.attachments_label.addClass("has-attachments")); + .insertAfter(this.add_attachment_wrapper); + + this.parent.find(".explore-btn").toggle(true); // show explore icon button if hidden } + get_file_url(attachment) { var file_url = attachment.file_url; if (!file_url) { diff --git a/frappe/public/js/frappe/form/templates/form_sidebar.html b/frappe/public/js/frappe/form/templates/form_sidebar.html index dcea2f4647..33ebb33cc4 100644 --- a/frappe/public/js/frappe/form/templates/form_sidebar.html +++ b/frappe/public/js/frappe/form/templates/form_sidebar.html @@ -54,17 +54,37 @@
  • + +
  • + + + +
  • + -
  • - -
  • +