feat: re-design attachment and image section

This commit is contained in:
Ejaaz Khan 2025-12-18 17:44:27 +05:30
parent 424222dc81
commit fbe22accb1
6 changed files with 95 additions and 49 deletions

View file

@ -182,7 +182,7 @@ def get_milestones(doctype, name):
def get_attachments(dt, dn):
return frappe.get_all(
"File",
fields=["name", "file_name", "file_url", "is_private"],
fields=["name", "file_name", "file_url", "is_private", "file_type", "file_size"],
filters={"attached_to_name": str(dn), "attached_to_doctype": dt},
)

View file

@ -312,8 +312,8 @@ frappe.get_data_pill = (
style = "";
if (colored) {
color = frappe.get_palette(label);
style = `background-color: var(${color[0]}); color: var(${color[1]})`;
}
style = `background-color: var(${color[0]}); color: var(${color[1]})`;
let data_pill_wrapper = $(`
<button class="data-pill btn" style="${style}">
<div class="flex align-center ellipsis">

View file

@ -113,47 +113,68 @@ frappe.ui.form.Attachments = class Attachments {
}
add_attachment(attachment) {
var file_name = attachment.file_name;
var file_url = this.get_file_url(attachment);
var fileid = attachment.name;
if (!file_name) {
file_name = file_url;
}
let file_name = attachment.file_name || this.get_file_url(attachment);
let file_url = this.get_file_url(attachment);
let fileid = attachment.name;
let me = this;
var me = this;
let $attachment_action = $(`<div></div>`);
let file_label = `
<a href="${file_url}" target="_blank" title="${frappe.utils.escape_html(file_name)}"
class="ellipsis attachment-file-label"
>
let $file_label = $(`
<a href="${file_url}" target="_blank" title="${frappe.utils.escape_html(
file_name
)}" class="ellipsis attachment-file-label">
<span>${frappe.utils.xss_sanitise(file_name)}</span>
</a>`;
</a>
`);
$attachment_action.append($file_label);
let remove_action = null;
if (this.can_delete_attachment()) {
remove_action = function (target_id) {
frappe.confirm(__("Are you sure you want to delete the attachment?"), function () {
let target_attachment = me
.get_attachments()
.find((attachment) => attachment.name === target_id);
let to_be_removed = me
.get_attachments()
.filter(
(attachment) => attachment.file_name === target_attachment.file_name
);
to_be_removed.forEach((attachment) => me.remove_attachment(attachment.name));
});
return false;
};
let $delete_attachment = $(`
<button class="btn btn-link attachment-remove-btn float-right">
${frappe.utils.icon("x")}
</button>
`);
$delete_attachment.on("click", () => {
me.delete_attachment(fileid);
});
$attachment_action.append($delete_attachment);
}
const icon = `<a href="/desk/file/${fileid}" class="attachment-icon">
${frappe.utils.icon(attachment.is_private ? "es-line-lock" : "es-line-unlock", "sm ml-0")}
</a>`;
const $attachment_meta = $(`
<div class="mt-1">
<a href="/desk/file/${fileid}" class="attachment-icon">
${frappe.utils.icon(attachment.is_private ? "es-line-lock" : "es-line-unlock", "sm ml-0")}
</a>
<span class="file-type">${attachment.file_type}</span>
<span class="file-size">
${frappe.form.formatters.FileSize(attachment.file_size)}
</span>
</div>
`);
$(`<div class="attachment-row"></div>`)
.append(frappe.get_data_pill(file_label, fileid, remove_action, icon))
.insertAfter(this.add_attachment_wrapper);
// Final row
let $row = $('<div class="attachment-row"></div>');
$row.append($attachment_action);
$row.append($attachment_meta);
$row.insertAfter(this.add_attachment_wrapper);
}
delete_attachment(target_id) {
let me = this;
frappe.confirm(__("Are you sure you want to delete the attachment?"), function () {
let target_attachment = me
.get_attachments()
.find((attachment) => attachment.name === target_id);
let to_be_removed = me
.get_attachments()
.filter((attachment) => attachment.file_name === target_attachment.file_name);
to_be_removed.forEach((attachment) => me.remove_attachment(attachment.name));
});
}
can_delete_attachment() {

View file

@ -16,6 +16,7 @@ frappe.ui.form.Sidebar = class {
doctype: this.frm.doctype,
frm: this.frm,
can_write: frappe.model.can_write(this.frm.doctype, this.frm.docname),
image_field: this.frm.meta.image_field ?? false,
});
this.sidebar = $('<div class="form-sidebar overlay-sidebar hidden-xs hidden-sm"></div>')

View file

@ -27,11 +27,11 @@
</div>
</div>
<div class="sidebar-section sidebar-meta-details border-bottom">
<div class="form-details flex justify-between">
<div class="form-details flex {{image_field ? "justify-center" : "justify-between"}}">
<span class="ellipsis mr-3 bold">{%= frm.get_title() %}</span>
<span class="form-name-copy" data-copy="{{frm.get_title()}}">{%= frappe.utils.icon("copy")%}</span>
</div>
<div class="form-name-container mt-2 flex justify-between">
<div class="form-name-container mt-2 flex {{image_field ? "justify-center" : "justify-between"}}">
<span class="ellipsis mr-3">{%= frm.doc.name %}</span>
<span class="indicator-pill whitespace-nowrap"></span>
</div>

View file

@ -81,6 +81,7 @@
position: relative;
width: fit-content;
height: fit-content;
margin: 0 auto;
}
.sidebar-image,
@ -293,19 +294,42 @@ body[data-route^="Form"] {
}
}
.attachment-row {
.data-pill {
background-color: unset;
box-shadow: none;
padding-left: 0px !important;
.attachment-file-label {
max-width: 150px;
display: block;
margin-left: var(--margin-xs);
text-align: left;
margin: var(--margin-sm) 0;
padding: var(--padding-sm);
.attachment-file-label {
max-width: 150px;
margin-left: var(--margin-xs);
text-align: left;
}
.attachment-icon {
line-height: 0;
}
.file-type,
.file-size {
color: var(--text-light);
}
.attachment-remove-btn {
display: none;
}
.file-type {
position: relative;
margin-right: 6px;
&::after {
content: ".";
width: 5px;
height: 2px;
display: inline-block;
position: absolute;
bottom: 32px;
font-size: 25px;
right: -7px;
}
.attachment-icon {
line-height: 0;
}
&:hover {
background-color: var(--subtle-fg);
border-radius: var(--border-radius-sm);
.attachment-remove-btn {
display: block;
}
}
}