Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions frappe/core/doctype/report/report.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"report_type",
"letter_head",
"add_total_row",
"enable_card_view_in_summary",
"disabled",
"prepared_report",
"timeout",
Expand Down Expand Up @@ -190,12 +191,18 @@
"fieldname": "timeout",
"fieldtype": "Int",
"label": "Timeout (In Seconds)"
},
{
"default": "0",
"fieldname": "enable_card_view_in_summary",
"fieldtype": "Check",
"label": "Enable Card View in Summary"
}
],
"idx": 1,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-08-31 20:34:10.018811",
"modified": "2025-07-04 14:04:43.497377",
"modified_by": "Administrator",
"module": "Core",
"name": "Report",
Expand Down Expand Up @@ -248,4 +255,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}
2 changes: 1 addition & 1 deletion frappe/core/doctype/report/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Report(Document):
add_total_row: DF.Check
columns: DF.Table[ReportColumn]
disabled: DF.Check
enable_card_view_in_summary: DF.Check
filters: DF.Table[ReportFilter]
is_standard: DF.Literal["No", "Yes"]
javascript: DF.Code | None
Expand All @@ -46,7 +47,6 @@ class Report(Document):
report_type: DF.Literal["Report Builder", "Query Report", "Script Report", "Custom Report"]
roles: DF.Table[HasRole]
timeout: DF.Int

# end: auto-generated types
def validate(self):
"""only administrator can save standard report"""
Expand Down
74 changes: 71 additions & 3 deletions frappe/public/js/frappe/views/reports/query_report.js
Original file line number Diff line number Diff line change
Expand Up @@ -770,13 +770,81 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
}

render_summary(data) {
data.forEach((summary) => {
frappe.utils.build_summary_item(summary).appendTo(this.$summary);
});
this.$summary.empty();

// Check if the report enable card view
if (this.report_doc.enable_card_view_in_summary) {
let html = `<div class="report-summary-card-container">`;

let section_label = '';
let section_rows = [];

data.forEach((item, index) => {
if (item.datatype === "Section Break") {
// render last section if exists
if (section_rows.length > 0) {
html += this.build_card(section_label, section_rows);
section_rows = [];
}
section_label = item.label;
} else {
section_rows.push(item);
}
});

// render final section
if (section_rows.length > 0) {
html += this.build_card(section_label, section_rows);
}
html += `</div>`;
this.$summary.html(html);

// Remove border-bottom from summary section
$('.report-summary').css('border-bottom', 'none');
}
else {
data.forEach((summary) => {
frappe.utils.build_summary_item(summary).appendTo(this.$summary);
});
}
this.$summary.show();
}

// Add this helper method
build_card(title, rows) {
let card = `
<div class="report-summary-card">
<h4 style="margin: 0 0 10px 0; font-size: 16px;">${title}</h4>
<table style="width:100%; border-collapse: collapse;">
<tbody>
`;

rows.forEach(item => {
const value = item.datatype === "Percent" ? `${item.value}%` : frappe.format(item.value, { fieldtype: item.datatype });
const color = {
green: "#28a745",
red: "#dc3545",
blue: "#007bff",
orange: "#fd7e14",
purple: "#6f42c1"
}[item.indicator] || "#333";

card += `
<tr>
<td style="padding: 4px 0;">${item.label}</td>
<td style="text-align: right; font-weight: bold; color: ${color}; padding: 4px 0;">${value}</td>
</tr>`;
});

card += `
</tbody>
</table>
</div>
`;

return card;
}

get_query_params() {
const query_string = frappe.utils.get_query_string(frappe.get_route_str());
return frappe.utils.get_query_params(query_string);
Expand Down
21 changes: 21 additions & 0 deletions frappe/public/scss/desk/report.scss
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,27 @@
}
}

.report-summary-card-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
width: 100%;
gap: 16px;
}

.report-summary-card {
flex: 1 1 23%;
box-sizing: border-box;
margin-bottom: 16px;
border: 1px solid #ddd;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0,0,0,0.05);
padding: 12px 16px;
background-color: #fff;
min-width: 250px;
}


.report-footer {
border-top: 1px solid var(--border-color);
@include get_textstyle("sm", "regular");
Expand Down
Loading