Merge pull request #35163 from iamejaaz/remove-list-sidebar

feat: userwise list filters
This commit is contained in:
Ejaaz Khan 2025-12-11 10:46:32 +05:30 committed by GitHub
commit fa85db7cd0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 79 additions and 129 deletions

View file

@ -889,13 +889,17 @@ class FilterArea {
const doctype_fields = this.list_view.meta.fields;
const title_field = this.list_view.meta.title_field;
const user_setting_fields =
frappe.get_user_settings(this.list_view.doctype)?.group_by_fields || [];
fields = fields.concat(
doctype_fields
.filter(
(df) =>
(df.fieldname === title_field ||
(df.in_standard_filter && frappe.model.is_value_type(df.fieldtype))) &&
((df.in_standard_filter ||
user_setting_fields.includes(df.fieldname)) &&
frappe.model.is_value_type(df.fieldtype))) &&
frappe.perm.has_perm(this.list_view.doctype, df.permlevel)
)
.map((df) => {

View file

@ -39,12 +39,6 @@ frappe.views.ListSidebar = class ListSidebar {
this.reload_stats();
});
}
if (frappe.user.has_role("System Manager")) {
this.add_insights_banner();
this.add_crm_banner();
this.add_helpdesk_banner();
}
}
setup_views() {
@ -280,67 +274,4 @@ frappe.views.ListSidebar = class ListSidebar {
this.sidebar.find(".stat-no-records").remove();
this.get_stats();
}
add_banner(message, link, cta) {
try {
this.banner = $(`
<div class="sidebar-section">
${message} <a href="${link}" target="_blank" style="color: var(--text-color)">${cta} &rarr; </a>
</div>
`).appendTo(this.sidebar);
} catch (error) {
console.error(error);
}
}
add_insights_banner() {
if (cint(frappe.boot.sysdefaults.disable_product_suggestion)) {
return;
}
if (this.list_view.view != "Report") {
return;
}
if (localStorage.getItem("show_insights_banner") == "false") {
return;
}
const message = __("Get more insights with");
const link = "https://frappe.io/s/insights";
const cta = "Frappe Insights";
this.add_banner(message, link, cta);
}
add_crm_banner() {
if (cint(frappe.boot.sysdefaults.disable_product_suggestion)) {
return;
}
if (this.list_view.meta.module != "CRM" || this.list_view.view != "List") {
return;
}
const message = "";
const link =
"https://frappe.io/crm?utm_source=crm-sidebar&utm_medium=sidebar&utm_campaign=frappe-ad";
const cta = __("Switch to Frappe CRM for smarter sales");
this.add_banner(message, link, cta);
}
add_helpdesk_banner() {
if (cint(frappe.boot.sysdefaults.disable_product_suggestion)) {
return;
}
if (this.list_view.meta.module != "Support" || this.list_view.view != "List") {
return;
}
const message = "";
const link =
"https://frappe.io/helpdesk?utm_source=support-sidebar&utm_medium=sidebar&utm_campaign=frappe-ad";
const cta = __("Upgrade your support experience with Frappe Helpdesk");
this.add_banner(message, link, cta);
}
};

View file

@ -11,45 +11,10 @@ frappe.views.ListGroupBy = class ListGroupBy {
this.group_by_fields = this.group_by_fields.concat(this.user_settings.group_by_fields);
}
this.render_group_by_items();
this.make_group_by_fields_modal();
this.setup_dropdown();
this.setup_filter_by();
}
make_group_by_fields_modal() {
let d = new frappe.ui.Dialog({
title: __("Select Filters"),
fields: this.get_group_by_dropdown_fields(),
});
d.set_primary_action(__("Save"), ({ group_by_fields }) => {
frappe.model.user_settings.save(
this.doctype,
"group_by_fields",
group_by_fields || null
);
this.group_by_fields = group_by_fields
? ["assigned_to", "owner", ...group_by_fields]
: ["assigned_to", "owner"];
this.render_group_by_items();
this.setup_dropdown();
d.hide();
});
d.$body.prepend(`
<div class="filters-search">
<input type="text"
placeholder="${__("Search")}"
data-element="search" class="form-control input-xs">
</div>
`);
this.page.sidebar.find(".add-list-group-by a").on("click", () => {
frappe.utils.setup_search(d.$body, ".unit-checkbox", ".label-area");
d.show();
});
}
make_wrapper() {
this.$wrapper = this.sidebar.sidebar.find(".list-group-by");
let html = `
@ -141,25 +106,6 @@ frappe.views.ListGroupBy = class ListGroupBy {
frappe.utils.setup_search($dropdown, ".group-by-item", ".group-by-value", "data-name");
}
get_group_by_dropdown_fields() {
let group_by_fields = [];
let fields = this.list_view.meta.fields.filter((f) =>
["Select", "Link", "Data", "Int", "Check"].includes(f.fieldtype)
);
group_by_fields.push({
label: __(this.doctype),
fieldname: "group_by_fields",
fieldtype: "MultiCheck",
columns: 2,
options: fields.map((df) => ({
label: __(df.label, null, df.parent),
value: df.fieldname,
checked: this.group_by_fields.includes(df.fieldname),
})),
});
return group_by_fields;
}
get_group_by_count(field) {
let current_filters = this.list_view.get_filters_for_args();

View file

@ -1990,6 +1990,14 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
});
}
items.push({
label: __("Edit Filters", null, "Edit filters of List View"),
action: () => {
this.make_group_by_fields_modal();
},
standard: true,
});
if (frappe.user.has_role("System Manager")) {
if (this.get_view_settings) {
items.push(this.get_view_settings());
@ -1999,6 +2007,65 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
return items;
}
make_group_by_fields_modal() {
let d = new frappe.ui.Dialog({
title: __("Select Filters"),
fields: this.get_group_by_dropdown_fields(),
});
d.set_primary_action(__("Save"), ({ group_by_fields }) => {
frappe.model.user_settings.save(
this.doctype,
"group_by_fields",
group_by_fields || null
);
this.group_by_fields = group_by_fields
? ["assigned_to", "owner", ...group_by_fields]
: ["assigned_to", "owner"];
d.hide();
frappe.msgprint(__("Saving Changes..."));
setTimeout(() => {
location.reload();
}, 1500);
});
d.$body.prepend(`
<div class="filters-search">
<input type="text"
placeholder="${__("Search")}"
data-element="search" class="form-control input-xs">
</div>
`);
frappe.utils.setup_search(d.$body, ".unit-checkbox", ".label-area");
d.show();
}
get_group_by_dropdown_fields() {
let group_by_fields = [];
let default_fields = ["assigned_to", "owner"];
default_fields = default_fields.concat(
frappe.get_user_settings(this.doctype)?.group_by_fields || []
);
let fields = this.meta.fields.filter((f) =>
["Select", "Link", "Data", "Int", "Check"].includes(f.fieldtype)
);
group_by_fields.push({
label: __(this.doctype),
fieldname: "group_by_fields",
fieldtype: "MultiCheck",
columns: 2,
options: fields.map((df) => ({
label: __(df.label, null, df.parent),
value: df.fieldname,
checked: default_fields.includes(df.fieldname),
})),
});
return group_by_fields;
}
get_view_settings() {
return {
label: __("List Settings", null, "Button in list view menu"),

View file

@ -2,17 +2,17 @@
<div class="container">
<div class="row flex-nowrap align-center page-head-content justify-between">
<div class="col-md-5 col-sm-6 col-xs-7 page-title">
<div class="flex fill-width title-area">
<div class="flex fill-width title-area ellipsis">
{% if (!frappe.is_mobile()) { %}
<ul class="nav d-sm-flex navbar-breadcrumbs"></ul>
<ul class="nav d-sm-flex navbar-breadcrumbs ellipsis"></ul>
{% endif %}
<span class="indicator-pill whitespace-nowrap"></span>
<button class="btn btn-default more-button hide">
<svg class="icon icon-sm">
<use href="#icon-dot-horizontal">
</use>
</svg>
</button>
<span class="indicator-pill whitespace-nowrap"></span>
</div>
</div>
<div class="flex col page-actions justify-content-end">

View file

@ -50,7 +50,7 @@
aria-label="{{ __("User Menu") }}"
>
<div> {{ avatar }} </div>
<div class="ml-2 avatar-name-email">
<div class="avatar-name-email ml-2 text-small">
<span>{{frappe.session.user_fullname}}</span>
<span class="text-secondary">{{frappe.session.user_email}}</span>
</div>

View file

@ -10,7 +10,7 @@
</span>
</a>
{% if (frappe.is_mobile()) { %}
<ul class="nav d-sm-flex navbar-breadcrumbs mobile-no-divider"></ul>
<ul class="nav d-sm-flex navbar-breadcrumbs mobile-no-divider ellipsis"></ul>
{% endif %}
<div class="collapse navbar-collapse justify-content-end">
{% if (frappe.boot.read_only) { %}

View file

@ -210,6 +210,7 @@ frappe.breadcrumbs = {
if (view === "form") {
let last_crumb = this.$breadcrumbs.find("li").last();
last_crumb.addClass("disabled");
last_crumb.addClass("ellipsis");
last_crumb.css("cursor", "copy");
last_crumb.click((event) => {
event.stopImmediatePropagation();

View file

@ -5,6 +5,7 @@
}
/*! This comment will be included even in compressed mode. */
.navbar-breadcrumbs {
flex-wrap: nowrap;
a {
text-decoration: none;
color: var(--ink-gray-5);