Merge branch 'rebrand-ui' of https://github.com/frappe/frappe into rebrand-ui

This commit is contained in:
Suraj Shetty 2020-06-12 12:17:18 +05:30
commit 36d41bfc35
19 changed files with 1852 additions and 1069 deletions

View file

@ -293,6 +293,7 @@
"public/js/frappe/list/list_view.js",
"public/js/frappe/list/list_factory.js",
"public/js/frappe/list/views.js",
"public/js/frappe/list/list_sidebar.js",
"public/js/frappe/list/list_sidebar.html",
"public/js/frappe/list/list_sidebar_stat.html",

View file

@ -25,6 +25,7 @@ frappe.views.BaseList = class BaseList {
this.setup_side_bar,
this.setup_main_section,
this.setup_view,
this.setup_view_menu,
].map((fn) => fn.bind(this));
this.init_promise = frappe.run_serially(tasks);
@ -164,9 +165,20 @@ frappe.views.BaseList = class BaseList {
this.page.set_title(this.page_title);
}
setup_view_menu() {
this.views_menu = this.page.add_custom_button_group(__(`View as {0}`, [this.view_name]), 'list');
this.views_list = new frappe.views.Views({
doctype: this.doctype,
parent: this.views_menu,
page: this.page,
list_view: this,
sidebar: this.list_sidebar,
});
}
set_menu_items() {
if (this.secondary_action) {
const $secondary_action = this.page.set_secondary_action(
const $secondary_action = this.page.set_secondary_action(
this.secondary_action.label,
this.secondary_action.action,
this.secondary_action.icon
@ -739,13 +751,13 @@ class FilterArea {
// utility function to validate view modes
frappe.views.view_modes = [
"List",
"Report",
"Dashboard",
"Gantt",
"Kanban",
"Calendar",
"Image",
"Inbox",
"Report",
"Dashboard",
];
frappe.views.is_valid = (view_mode) =>
frappe.views.view_modes.includes(view_mode);

View file

@ -1,96 +1,74 @@
<ul class="list-unstyled sidebar-menu visible-sm visible-xs">
<li>
<a class="navbar-home" href="#">
<img class="app-logo" src="{{ frappe.app.logo_url }}">
</a>
</li>
</ul>
<ul class="list-unstyled sidebar-menu user-actions hide">
<li class="divider"></li>
</ul>
<ul class="list-unstyled sidebar-menu standard-actions">
{% if frappe.model.can_get_report(doctype) %}
<li class="list-sidebar-label">Views</li>
<li class="divider visible-sm visible-xs"></li>
<li class="list-link">
<div class="btn-group">
<a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#" onclick="return false;">
{{ __("Reports") }} <span class="caret"></span>
</a>
<ul class="dropdown-menu reports-dropdown" role="menu">
<li><a href="#List/{{ doctype }}/Report">{{ __("Report Builder") }}</a></li>
</ul>
<ul class="list-unstyled sidebar-menu">
<div class="sidebar-section views-section hide">
<li class="list-sidebar-label">
</li>
<div class="current-view">
<li class="list-link">
<a class="btn btn-default btn-sm list-sidebar-button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
href="#"
>
<span class="text-muted selected-view">
</span>
<span>
<svg class="icon icon-xs">
<use xlink:href="#icon-select"></use>
</svg>
</span>
</a>
<ul class="dropdown-menu views-dropdown" role="menu">
</ul>
</li>
<li class="sidebar-action">
<a class="view-action"></a>
</li>
</div>
</li>
{% endif %}
<li class="divider"></li>
<li class="list-link" data-view="List">
<a href="#List/{%= doctype %}/List">{%= __("List") %}</a></li>
<li class="list-link" data-view="Dashboard">
<a href="#List/{%= doctype %}/Dashboard">{%= __("Dashboard") %}</a></li>
<li class="hide list-link" data-view="Image">
<a href="#List/{%= doctype %}/Image">{%= __("Images") %}</a></li>
<li class="hide list-link" data-view="Gantt">
<a href="#List/{%= doctype %}/Gantt">{%= __("Gantt") %}</a></li>
<li class="hide tree-link">
<a href="#Tree/{%= doctype %}">{%= __("Tree") %}</a></li>
<li class="hide list-link" data-view="Calendar">
<a href="#List/{%= doctype %}/Calendar">{%= __("Calendar") %}</a></li>
<li class="hide list-link" data-view="Kanban">
<div class="btn-group">
<a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#" onclick="return false;">
{{ __("Kanban") }} <span class="caret"></span>
</a>
<ul class="dropdown-menu kanban-dropdown" style="max-height: 300px; overflow-y: auto;" role="menu">
<li class="new-kanban-board"><a href="#" onclick="return false;">{{ __("New Kanban Board") }}</a></li>
</ul>
</div>
<div class="sidebar-section filter-section">
<li class="list-sidebar-label">
{{ __("Filter By") }}
</li>
<div class="list-group-by">
</div>
</li>
<li class="hide list-link" data-view="Inbox">
<div class="btn-group">
<a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#" onclick="return false;">
{{ __("Email Inbox") }} <span class="caret"></span>
</a>
<ul class="dropdown-menu email-account-dropdown" style="max-height: 300px; overflow-y: auto;" role="menu">
</ul>
<div class="list-tags">
<li class="list-stats list-link">
<a
class="btn btn-default btn-sm list-sidebar-button"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
href="#"
>
<span class="text-muted">{{ __("Tags") }}</span>
<span>
<svg class="icon icon-xs">
<use xlink:href="#icon-select"></use>
</svg>
</span>
</a>
<ul class="dropdown-menu list-stats-dropdown" role="menu">
<div class="dropdown-search">
<input type="text" placeholder="Search" data-element="search" class="form-control input-xs">
</div>
</ul>
</li>
<li class="sidebar-action show-tags">
<a class="list-tag-preview">{{ __("Show Tags") }}</a>
</li>
</div>
</li>
{% if(frappe.help.has_help(doctype)) { %}
<li><a class="help-link list-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li>
{% } %}
</ul>
<ul class="list-unstyled sidebar-menu list-group-by">
</div>
</ul>
<ul class="list-unstyled sidebar-menu sidebar-stat">
<li class="list-sidebar-label stat-label">{{ __("Tags") }}</li>
<li class="list-stats list-link">
<div class="btn-group">
<a class = "dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" href="#" onclick="return false;">
{{ __("Tags") }} <span class="caret"></span>
</a>
<ul class="dropdown-menu list-stats-dropdown" role="menu">
<div class="dropdown-search">
<input type="text" placeholder="Search" data-element="search" class="form-control input-xs">
</div>
</ul>
</div>
</li>
<li class="list-link" style="margin-top: 10px;">
<a class="list-tag-preview hidden-xs text-muted">{{ __("Show Tags") }}</a>
</li>
</ul>
<ul class="list-unstyled sidebar-menu charts-menu hide">
<li class="h6">{%= __("Charts") %}</li>
<li class="list-link">
<a class="toggle-charts">{%= __("Toggle Charts") %}</a>
</li>
<li class="list-link">
<a class="configure-charts hidden">{%= __("Configure Charts") %}</a>
</li>
</ul>
<ul class="list-unstyled sidebar-menu list-filters"></ul>
<ul class="list-unstyled close-sidebar-button visible-xs visible-sm">
<li class="divider"></li>
<li class="close-sidebar">{{ __("Close") }}</li>
</ul>
<!-- {% if(frappe.help.has_help(doctype)) { %} -->
<!-- <div class="sidebar-section help-section">
<li><a class="help-link list-link" data-doctype="{{ doctype }}">{{ __("Help") }}</a></li>
</div> -->
<!-- {% } %} -->

View file

@ -1,6 +1,5 @@
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
// MIT License. See license.txt
import ListFilter from './list_filter';
frappe.provide('frappe.views');
// opts:
@ -23,13 +22,6 @@ frappe.views.ListSidebar = class ListSidebar {
.html(sidebar_content)
.appendTo(this.page.sidebar.empty());
this.setup_reports();
this.setup_list_filter();
this.setup_views();
this.setup_kanban_boards();
this.setup_calendar_view();
this.setup_email_inbox();
this.setup_keyboard_shortcuts();
this.setup_list_group_by();
// do not remove
@ -46,193 +38,6 @@ frappe.views.ListSidebar = class ListSidebar {
}
setup_views() {
var show_list_link = false;
if (frappe.views.calendar[this.doctype]) {
this.sidebar.find('.list-link[data-view="Calendar"]').removeClass("hide");
this.sidebar.find('.list-link[data-view="Gantt"]').removeClass('hide');
show_list_link = true;
}
//show link for kanban view
this.sidebar.find('.list-link[data-view="Kanban"]').removeClass('hide');
if (this.doctype === "Communication" && frappe.boot.email_accounts.length) {
this.sidebar.find('.list-link[data-view="Inbox"]').removeClass('hide');
show_list_link = true;
}
if (frappe.treeview_settings[this.doctype] || frappe.get_meta(this.doctype).is_tree) {
this.sidebar.find(".tree-link").removeClass("hide");
}
this.current_view = 'List';
var route = frappe.get_route();
if (route.length > 2 && frappe.views.view_modes.includes(route[2])) {
this.current_view = route[2];
if (this.current_view === 'Kanban') {
this.kanban_board = route[3];
} else if (this.current_view === 'Inbox') {
this.email_account = route[3];
}
}
// disable link for current view
this.sidebar.find('.list-link[data-view="' + this.current_view + '"] a')
.attr('disabled', 'disabled').addClass('disabled');
//enable link for Kanban view
this.sidebar.find('.list-link[data-view="Kanban"] a, .list-link[data-view="Inbox"] a')
.attr('disabled', null).removeClass('disabled');
// show image link if image_view
if (this.list_view.meta.image_field) {
this.sidebar.find('.list-link[data-view="Image"]').removeClass('hide');
show_list_link = true;
}
if (show_list_link) {
this.sidebar.find('.list-link[data-view="List"]').removeClass('hide');
}
}
setup_reports() {
// add reports linked to this doctype to the dropdown
var me = this;
var added = [];
var dropdown = this.page.sidebar.find('.reports-dropdown');
var divider = false;
var add_reports = function(reports) {
$.each(reports, function(name, r) {
if (!r.ref_doctype || r.ref_doctype == me.doctype) {
var report_type = r.report_type === 'Report Builder' ?
`List/${r.ref_doctype}/Report` : 'query-report';
var route = r.route || report_type + '/' + (r.title || r.name);
if (added.indexOf(route) === -1) {
// don't repeat
added.push(route);
if (!divider) {
me.get_divider().appendTo(dropdown);
divider = true;
}
$('<li><a href="#' + route + '">' +
__(r.title || r.name) + '</a></li>').appendTo(dropdown);
}
}
});
};
// from reference doctype
if (this.list_view.settings.reports) {
add_reports(this.list_view.settings.reports);
}
// Sort reports alphabetically
var reports = Object.values(frappe.boot.user.all_reports).sort((a,b) => a.title.localeCompare(b.title)) || [];
// from specially tagged reports
add_reports(reports);
}
setup_list_filter() {
this.list_filter = new ListFilter({
wrapper: this.page.sidebar.find('.list-filters'),
doctype: this.doctype,
list_view: this.list_view
});
}
setup_kanban_boards() {
const $dropdown = this.page.sidebar.find('.kanban-dropdown');
frappe.views.KanbanView.setup_dropdown_in_sidebar(this.doctype, $dropdown);
}
setup_calendar_view() {
const doctype = this.doctype;
frappe.db.get_list('Calendar View', {
filters: {
reference_doctype: doctype
}
}).then(result => {
if (!(result && Array.isArray(result) && result.length)) return;
const calendar_views = result;
const $link_calendar = this.sidebar.find('.list-link[data-view="Calendar"]');
let default_link = '';
if (frappe.views.calendar[this.doctype]) {
// has standard calendar view
default_link = `<li><a href="#List/${doctype}/Calendar/Default">
${ __("Default") }</a></li>`;
}
const other_links = calendar_views.map(
calendar_view => `<li><a href="#List/${doctype}/Calendar/${calendar_view.name}">
${ __(calendar_view.name) }</a>
</li>`
).join('');
const dropdown_html = `
<div class="btn-group">
<a class="dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
${ __("Calendar") } <span class="caret"></span>
</a>
<ul class="dropdown-menu calendar-dropdown" style="max-height: 300px; overflow-y: auto;">
${default_link}
${other_links}
</ul>
</div>
`;
$link_calendar.removeClass('hide');
$link_calendar.html(dropdown_html);
});
}
setup_email_inbox() {
// get active email account for the user and add in dropdown
if (this.doctype != "Communication")
return;
let $dropdown = this.page.sidebar.find('.email-account-dropdown');
let divider = false;
if (has_common(frappe.user_roles, ["System Manager", "Administrator"])) {
$(`<li class="new-email-account"><a>${__("New Email Account")}</a></li>`)
.appendTo($dropdown);
}
let accounts = frappe.boot.email_accounts;
accounts.forEach((account) => {
let email_account = (account.email_id == "All Accounts") ? "All Accounts" : account.email_account;
let route = ["List", "Communication", "Inbox", email_account].join('/');
let display_name = ["All Accounts", "Sent Mail", "Spam", "Trash"].includes(account.email_id) ? __(account.email_id) : account.email_id;
if (!divider) {
this.get_divider().appendTo($dropdown);
divider = true;
}
$(`<li><a href="#${route}">${display_name}</a></li>`).appendTo($dropdown);
if (account.email_id === "Sent Mail")
divider = false;
});
$dropdown.find('.new-email-account').click(function() {
frappe.new_doc("Email Account");
});
}
setup_keyboard_shortcuts() {
this.sidebar.find('.list-link > a, .list-link > .btn-group > a').each((i, el) => {
frappe.ui.keys
.get_shortcut_group(this.page)
.add($(el));
});
}
setup_list_group_by() {
this.list_group_by = new frappe.views.ListGroupBy({
doctype: this.doctype,
@ -255,7 +60,7 @@ frappe.views.ListSidebar = class ListSidebar {
stats: me.stats,
doctype: me.doctype,
// wait for list filter area to be generated before getting filters, or fallback to default filters
filters: (me.list_view.filter_area ? me.list_filter.get_current_filters() : me.default_filters) || []
filters: (me.list_view.filter_area ? me.list_view.get_filters_for_args() : me.default_filters) || []
},
callback: function(r) {
me.render_stat("_user_tags", (r.message.stats || {})["_user_tags"]);

View file

@ -1,4 +1,3 @@
frappe.provide('frappe.views');
frappe.views.ListGroupBy = class ListGroupBy {
@ -8,8 +7,10 @@ frappe.views.ListGroupBy = class ListGroupBy {
this.user_settings = frappe.get_user_settings(this.doctype);
this.group_by_fields = ['assigned_to', 'owner'];
if(this.user_settings.group_by_fields) {
this.group_by_fields = this.group_by_fields.concat(this.user_settings.group_by_fields);
if (this.user_settings.group_by_fields) {
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();
@ -18,23 +19,31 @@ frappe.views.ListGroupBy = class ListGroupBy {
}
make_group_by_fields_modal() {
let d = new frappe.ui.Dialog ({
title: __("Select Filters"),
fields: this.get_group_by_dropdown_fields()
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.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();
d.hide();
});
d.$body.prepend(`<div class="filters-search">
<input type="text" placeholder="${__('Search')}" data-element="search" class="form-control input-xs">
<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", () => {
this.page.sidebar.find('.add-list-group-by a').on('click', () => {
frappe.utils.setup_search(d.$body, '.unit-checkbox', '.label-area');
d.show();
});
@ -43,14 +52,11 @@ frappe.views.ListGroupBy = class ListGroupBy {
make_wrapper() {
this.$wrapper = this.sidebar.sidebar.find('.list-group-by');
let html = `
<li class="list-sidebar-label">
${__('Filter By')}
</li>
<div class="list-group-by-fields">
</div>
<li class="add-list-group-by list-link">
<a class="add-group-by hidden-xs text-muted">
${__("Add Fields")} <i class="octicon octicon-plus" style="margin-left: 2px;"></i>
<li class="add-list-group-by sidebar-action">
<a class="add-group-by hidden-xs">
+ ${__('Add Fields')}
</a>
</li>
`;
@ -74,19 +80,19 @@ frappe.views.ListGroupBy = class ListGroupBy {
}
return `<li class="group-by-field list-link">
<div class="btn-group">
<a class = "dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
<a class="btn btn-default btn-sm list-sidebar-button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
data-label="${label}" data-fieldname="${fieldname}" data-fieldtype="${fieldtype}"
href="#" onclick="return false;">
${__(label)} <span class="caret"></span>
<span class="text-muted ellipsis">${__(label)}</span>
<span>${frappe.utils.icon('select', 'xs')}</span>
</a>
<ul class="dropdown-menu group-by-dropdown" role="menu">
<li><div class="list-loading text-center group-by-loading text-muted">
${__("Loading...")}
<li>
<div class="empty-state group-by-loading">
${__('Loading...')}
</div>
</li>
</ul>
</div>
</li>`;
};
let html = this.group_by_fields.map(get_item_html).join('');
@ -94,18 +100,27 @@ frappe.views.ListGroupBy = class ListGroupBy {
}
setup_dropdown() {
this.$wrapper.on('click', '.group-by-field', (e)=> {
this.$wrapper.on('click', '.group-by-field', (e) => {
let dropdown = $(e.currentTarget).find('.group-by-dropdown');
let fieldname = $(e.currentTarget).find('a').attr('data-fieldname');
let fieldtype = $(e.currentTarget).find('a').attr('data-fieldtype');
this.get_group_by_count(fieldname).then(field_count_list => {
let fieldname = $(e.currentTarget)
.find('a')
.attr('data-fieldname');
let fieldtype = $(e.currentTarget)
.find('a')
.attr('data-fieldtype');
this.get_group_by_count(fieldname).then((field_count_list) => {
if (field_count_list.length) {
this.render_dropdown_items(field_count_list, fieldtype, dropdown);
frappe.utils.setup_search(dropdown, '.group-by-item', '.group-by-value', 'data-name');
frappe.utils.setup_search(
dropdown,
'.group-by-item',
'.group-by-value',
'data-name'
);
} else {
dropdown.html(
`<div class="list-loading text-center group-by-empty text-muted">
${__("No filters found")}
`<div class="empty-state group-by-empty">
${__('No filters found')}
</div>`
);
}
@ -115,18 +130,19 @@ frappe.views.ListGroupBy = class ListGroupBy {
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));
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),
value: df.fieldname,
checked: this.group_by_fields.includes(df.fieldname)
}))
options: fields.map((df) => ({
label: __(df.label),
value: df.fieldname,
checked: this.group_by_fields.includes(df.fieldname),
})),
});
return group_by_fields;
}
@ -135,25 +151,32 @@ frappe.views.ListGroupBy = class ListGroupBy {
let current_filters = this.list_view.get_filters_for_args();
// remove filter of the current field
current_filters =
current_filters.filter((f_arr) => !f_arr.includes(field === 'assigned_to' ? '_assign': field));
current_filters = current_filters.filter(
(f_arr) => !f_arr.includes(field === 'assigned_to' ? '_assign' : field)
);
let args = {
let args = {
doctype: this.doctype,
current_filters: current_filters,
field: field,
};
return frappe.call('frappe.desk.listview.get_group_by_count', args).then((r) => {
let field_counts = r.message || [];
field_counts = field_counts.filter(f => f.count !== 0);
let current_user = field_counts.find(f => f.name === frappe.session.user);
field_counts = field_counts.filter(f => !['Guest', 'Administrator', frappe.session.user].includes(f.name));
// Set frappe.session.user on top of the list
if (current_user) field_counts.unshift(current_user);
return field_counts;
});
return frappe
.call('frappe.desk.listview.get_group_by_count', args)
.then((r) => {
let field_counts = r.message || [];
field_counts = field_counts.filter((f) => f.count !== 0);
let current_user = field_counts.find(
(f) => f.name === frappe.session.user
);
field_counts = field_counts.filter(
(f) =>
!['Guest', 'Administrator', frappe.session.user].includes(f.name)
);
// Set frappe.session.user on top of the list
if (current_user) field_counts.unshift(current_user);
return field_counts;
});
}
render_dropdown_items(fields, fieldtype, dropdown) {
@ -162,20 +185,22 @@ frappe.views.ListGroupBy = class ListGroupBy {
if (label === frappe.session.user) {
label = __('Me');
} else if (fieldtype && fieldtype == 'Check') {
label = label == '0'? __('No'): __('Yes');
label = label == '0' ? __('No') : __('Yes');
}
let value = field.name == null ? '' : encodeURIComponent(field.name);
return `<li class="group-by-item" data-value="${value}">
<a class="badge-hover" href="#" onclick="return false;">
<span class="group-by-value" data-name="${field.name}">${label}</span>
<span class="badge pull-right group-by-count">${field.count}</span>
<a class="dropdown-item" href="#" onclick="return false;">
<span class="group-by-value ellipsis" data-name="${field.name}">${label}</span>
<span class="group-by-count">${field.count}</span>
</a>
</li>`;
};
let standard_html = `
<div class="dropdown-search">
<input type="text" placeholder="${__('Search')}" data-element="search" class="dropdown-search-input form-control input-xs">
<input type="text" placeholder="${__(
'Search'
)}" data-element="search" class="dropdown-search-input form-control input-xs">
</div>
`;
@ -186,27 +211,34 @@ frappe.views.ListGroupBy = class ListGroupBy {
setup_filter_by() {
this.$wrapper.on('click', '.group-by-item', (e) => {
let $target = $(e.currentTarget);
let fieldname = $target.parents('.group-by-field').find('a').data('fieldname');
let value = typeof $target.data('value') === 'string'
? decodeURIComponent($target.data('value').trim())
: $target.data('value');
fieldname = fieldname === 'assigned_to' ? '_assign': fieldname;
let fieldname = $target
.parents('.group-by-field')
.find('a')
.data('fieldname');
let value =
typeof $target.data('value') === 'string'
? decodeURIComponent($target.data('value').trim())
: $target.data('value');
fieldname = fieldname === 'assigned_to' ? '_assign' : fieldname;
return this.list_view.filter_area.remove(fieldname)
.then(() => {
let operator = '=';
if (value === '') {
operator = 'is';
value = 'not set';
}
if (fieldname === '_assign') {
operator = 'like';
value = `%${value}%`;
}
return this.list_view.filter_area.remove(fieldname).then(() => {
let operator = '=';
if (value === '') {
operator = 'is';
value = 'not set';
}
if (fieldname === '_assign') {
operator = 'like';
value = `%${value}%`;
}
return this.list_view.filter_area.add(this.doctype, fieldname, operator, value);
});
return this.list_view.filter_area.add(
this.doctype,
fieldname,
operator,
value
);
});
});
}
};

View file

@ -7,9 +7,9 @@
var stat_count = stat[i][1];
%}
<li>
<a class="stat-link badge-hover" data-label="{{ stat_label %}" data-field="{{ field %}" href="#" onclick="return false;">
<span class="badge pull-right" style="position: relative">{{ stat_count }}</span>
<a class="stat-link dropdown-item" data-label="{{ stat_label %}" data-field="{{ field %}" href="#" onclick="return false;">
<span class="stat-label">{{ __(stat_label) }}</span>
<span>{{ stat_count }}</span>
</a>
</li>
{% }

View file

@ -751,7 +751,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
doc[this.meta.title_field || ""] !== doc.name
) {
html += `
<div class="level-item hidden-xs hidden-sm ellipsis">
<div class="level-item ellipsis">
<a class="text-muted ellipsis" href="${this.get_form_link(doc)}">
${doc.name}
</a>
@ -784,12 +784,14 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList {
const comment_count = `<span class="${
!doc._comment_count ? "text-extra-muted" : ""
} comment-count">
<i class="octicon octicon-comment-discussion"></i>
<svg class="icon icon-sm">
<use xlink:href="#icon-small-message"></use>
</svg>
${doc._comment_count > 99 ? "99+" : doc._comment_count}
</span>`;
html += `
<div class="level-item hidden-xs list-row-activity">
<div class="level-item list-row-activity">
${modified}
${assigned_to}
${comment_count}

View file

@ -0,0 +1,264 @@
frappe.provide('frappe.views');
frappe.views.Views = class Views {
constructor(opts) {
$.extend(this, opts);
this.set_current_view();
this.setup_views();
}
add_view_to_menu(view, action) {
let $el = this.page.add_custom_menu_item(
this.parent,
view,
action,
true,
);
$el.parent().attr('data-view', view)
}
set_current_view() {
this.current_view = 'List';
var route = frappe.get_route();
if (route.length > 2 && frappe.views.view_modes.includes(route[2])) {
this.current_view = route[2];
if (this.current_view === 'Kanban') {
this.kanban_board = route[3];
} else if (this.current_view === 'Inbox') {
this.email_account = route[3];
}
}
}
setup_views() {
const views = {
'List': {
condition: true,
action: () => frappe.set_route(`List/${this.doctype}/List`)
},
'Report': {
condition: true,
action: () => frappe.set_route(`List/${this.doctype}/Report`),
current_view_handler: () => {
const reports = this.get_reports();
this.setup_dropdown_in_sidebar(
'Report',
reports,
{
label: __('Report Builder'),
action: () => frappe.set_route(`List/${this.doctype}/Report`)
}
);
}
},
'Dashboard': {
condition: true,
action: () => frappe.set_route(`List/${this.doctype}/Dashboard`)
},
'Calendar': {
condition: frappe.views.calendar[this.doctype],
action: () => frappe.set_route(`List/${this.doctype}/Calendar/Default`),
current_view_handler: () => {
this.get_calendars().then(calendars => {
this.setup_dropdown_in_sidebar(
'Calendar',
calendars,
);
});
}
},
'Gantt': {
condition: frappe.views.calendar[this.doctype],
action: () => frappe.set_route(`List/${this.doctype}/Gantt`)
},
'Inbox': {
condition: this.doctype === "Communication" && frappe.boot.email_accounts.length,
action: () => frappe.set_route(`List/${this.doctype}/Inbox`),
current_view_handler: () => {
const accounts = this.get_email_accounts();
let default_action;
if (has_common(frappe.user_roles, ["System Manager", "Administrator"])) {
default_action = {
label: __('New Email Account'),
action: () => frappe.new_doc("Email Account")
}
}
this.setup_dropdown_in_sidebar(
'Inbox',
accounts,
default_action,
);
}
},
'Image': {
condition: this.list_view.meta.image_field,
action: () => frappe.set_route(`List/${this.doctype}/Image`)
},
'Tree': {
condition: frappe.treeview_settings[this.doctype] || frappe.get_meta(this.doctype).is_tree,
action: () => frappe.set_route(`List/${this.doctype}/Tree`)
},
'Kanban': {
condition: true,
action: () => this.setup_kanban_boards(),
current_view_handler: () => {
frappe.views.KanbanView.get_kanbans(this.doctype).then((kanbans) => {
this.setup_dropdown_in_sidebar(
'Kanban',
kanbans,
{
label: __('New Kanban Board'),
action: () => frappe.views.KanbanView.show_kanban_dialog(this.doctype)
}
);
});
}
},
}
frappe.views.view_modes.forEach(view => {
if (this.current_view !== view && views[view].condition) {
this.add_view_to_menu(view, views[view].action);
}
if (this.current_view == view) {
views[view].current_view_handler && views[view].current_view_handler();
}
});
}
setup_dropdown_in_sidebar(view, items, default_action) {
const views_wrapper = this.sidebar.sidebar.find('.views-section');
views_wrapper.find('.list-sidebar-label').html(`${__(view)}`);
const $dropdown = views_wrapper.find('.views-dropdown');
let placeholder = `Select ${view}`;
let html = ``;
if (!items || !items.length) {
html = `<div class="empty-state">
${__('No {} Found', [view])}
</div>`;
} else {
items.map(item => {
if (item.name == frappe.get_route().slice(-1)[0]) {
placeholder = item.name;
}
html += `<li><a class="dropdown-item" href="#${item.route}">${item.name}</a></li>`;
});
}
views_wrapper.find('.selected-view').html(placeholder);
if (default_action) {
views_wrapper.find('.sidebar-action a').html(default_action.label);
views_wrapper.find('.sidebar-action a').click(() => default_action.action());
}
$dropdown.html(html);
views_wrapper.removeClass('hide');
}
get_reports() {
// add reports linked to this doctype to the dropdown
let added = [];
let reports_to_add = [];
let add_reports = (reports) => {
reports.map((r) => {
if (!r.ref_doctype || r.ref_doctype == this.doctype) {
const report_type = r.report_type === 'Report Builder' ?
`List/${r.ref_doctype}/Report` : 'query-report';
const route = r.route || report_type + '/' + (r.title || r.name);
if (added.indexOf(route) === -1) {
// don't repeat
added.push(route);
reports_to_add.push({name: r.title || r.name, route: route});
}
}
});
};
// from reference doctype
if (this.list_view.settings.reports) {
add_reports(this.list_view.settings.reports);
}
// Sort reports alphabetically
var reports = Object.values(frappe.boot.user.all_reports).sort((a,b) => a.title.localeCompare(b.title)) || [];
// from specially tagged reports
add_reports(reports);
return reports_to_add;
}
setup_kanban_boards() {
const last_opened_kanban = frappe.model.user_settings[this.doctype]['Kanban']
&& frappe.model.user_settings[this.doctype]['Kanban'].last_kanban_board;
if (last_opened_kanban) {
frappe.set_route(`List/${this.doctype}/Kanban/${last_opened_kanban}`);
} else {
frappe.views.KanbanView.show_kanban_dialog(this.doctype, true);
}
}
get_calendars() {
const doctype = this.doctype;
let calendars = [];
return frappe.db.get_list('Calendar View', {
filters: {
reference_doctype: doctype
}
}).then(result => {
if (!(result && Array.isArray(result) && result.length)) return;
if (frappe.views.calendar[this.doctype]) {
// has standard calendar view
calendars.push({
name: 'Default',
route: `List/${this.doctype}/Calendar/Default`
});
}
result.map(calendar => {
calendars.push({name: calendar.name, route: `List/${doctype}/Calendar/${calendar.name}`});
});
return calendars;
});
}
get_email_accounts() {
let accounts_to_add = [];
let accounts = frappe.boot.email_accounts;
accounts.forEach(account => {
let email_account = (account.email_id == "All Accounts") ? "All Accounts" : account.email_account;
let route = ["List", "Communication", "Inbox", email_account].join('/');
let display_name = ["All Accounts", "Sent Mail", "Spam", "Trash"].includes(account.email_id)
? __(account.email_id)
: account.email_account;
accounts_to_add.push({
name: display_name,
route: route
});
});
return accounts_to_add;
}
setup_keyboard_shortcuts() {
this.sidebar.find('.list-link > a, .list-link > .btn-group > a').each((i, el) => {
frappe.ui.keys
.get_shortcut_group(this.page)
.add($(el));
});
}
}

View file

@ -15,7 +15,7 @@
<!-- <span class="checked-items-status text-ellipsis text-muted small hide hidden-xs hidden-sm" style="margin-right: 20px;">## items selected</span> -->
<!-- <h6 class="ellipsis sub-heading hide text-muted"></h6> -->
<span class="page-icon-group hide hidden-xs hidden-sm"></span>
<div class="custom-actions hide hidden-xs hidden-sm"></div>
<div class="custom-actions hide"></div>
<!-- buttons -->
<div class="menu-btn-group hide">
<button type="button" class="btn btn-default btn-sm" data-toggle="dropdown" aria-expanded="false">

View file

@ -243,6 +243,16 @@ frappe.ui.Page = Class.extend({
});
},
add_custom_menu_item: function(parent, label, click, standard, shortcut) {
return this.add_dropdown_item({
label,
click,
standard,
parent: parent,
shortcut,
});
},
clear_menu: function() {
this.clear_btn_group(this.menu);
},
@ -574,7 +584,28 @@ frappe.ui.Page = Class.extend({
button.appendTo(this.custom_actions)
button.onclick = click;
return button
return button;
},
add_custom_button_group: function(label, icon) {
let custom_btn_group = $(`
<div class="custom-btn-group hide">
<button type="button" class="btn btn-default btn-sm" data-toggle="dropdown" aria-expanded="false">
<span class="hidden-xs">
${frappe.utils.icon(icon)}
<span class="custom-btn-group-label">${__(label)}</span>
<span class="caret"></span>
</span>
<span class="visible-xs">
${frappe.utils.icon(icon)}
</span>
</button>
<ul class="dropdown-menu" role="menu"></ul>
</div>
`);
this.custom_actions.removeClass('hide').append(custom_btn_group);
return custom_btn_group.find('.dropdown-menu');
},
add_dropdown_button: function(parent, label, click, icon) {

View file

@ -179,29 +179,33 @@ frappe.views.KanbanView = class KanbanView extends frappe.views.ListView {
};
frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown) {
// get kanban boards and append to dropdown
get_kanban_boards()
frappe.views.KanbanView.get_kanbans = function(doctype) {
let kanbans = [];
return get_kanban_boards()
.then((kanban_boards) => {
if (!kanban_boards) return;
if (kanban_boards) {
kanban_boards.forEach(board => {
let route = ['List', board.reference_doctype, 'Kanban', board.name].join('/');
kanbans.push({name: board.name, route: route});
});
}
$('<li role="separator" class="divider"></li>').appendTo($dropdown);
kanban_boards.forEach(board => {
const route = ['List', board.reference_doctype, 'Kanban', board.name].join('/');
$(`<li>
<a href="#${route}">
<span>${__(board.name)}</span>
${board.private ? '<i class="fa fa-lock fa-fw text-warning"></i>' : ''}
</a>
</li>
`).appendTo($dropdown);
});
return kanbans;
});
$dropdown.on('click', '.new-kanban-board', () => {
const dialog = new_kanban_dialog();
function get_kanban_boards() {
return frappe.call('frappe.desk.doctype.kanban_board.kanban_board.get_kanban_boards', { doctype })
.then(r => r.message);
}
}
frappe.views.KanbanView.show_kanban_dialog = function(doctype, show_existing) {
let dialog = null;
frappe.views.KanbanView.get_kanbans(doctype).then(kanbans => {
dialog = new_kanban_dialog(kanbans, show_existing);
dialog.show();
});
@ -225,19 +229,22 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown)
});
}
let dialog = null;
function new_kanban_dialog() {
function new_kanban_dialog(kanbans, show_existing) {
if (dialog) return dialog;
const fields = get_fields_for_dialog();
const fields = get_fields_for_dialog(kanbans.map(kanban=> kanban.name), show_existing);
let primary_action_label = fields.length > 1 ? __('Save') : '';
let primary_action = fields.length > 1 ?
({ board_name, field_name, project }) => {
make_kanban_board(board_name, field_name, project)
let primary_action_label = __('Save');
let primary_action = () => {
const values = dialog.get_values();
if (!values.selected_kanban || values.selected_kanban == 'Create New Board') {
make_kanban_board(values.board_name, values.field_name, values.project)
.then(() => dialog.hide(), (err) => frappe.msgprint(err));
} : null;
} else {
frappe.set_route(kanbans.find(kanban => kanban.name == values.selected_kanban).route);
}
}
dialog = new frappe.ui.Dialog({
title: __('New Kanban Board'),
@ -248,16 +255,33 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown)
return dialog;
}
function get_fields_for_dialog() {
function get_fields_for_dialog(kanban_options, show_existing=false) {
kanban_options.push('Create New Board');
let fields = [{
fieldtype: 'Data',
fieldname: 'board_name',
label: __('Kanban Board Name'),
reqd: 1,
description: ['Note', 'ToDo'].includes(doctype) ?
__('This Kanban Board will be private') : ''
}];
let fields = [
{
fieldtype: 'Select',
fieldname: 'selected_kanban',
label: __('Choose Kanban Board'),
reqd: 1,
depends_on: `eval: ${show_existing}`,
mandatory_depends_on: `eval: ${show_existing}`,
options: kanban_options,
},
{
fieldname: 'new_kanban_board_sb',
fieldtype: 'Section Break',
depends_on: `eval: !${show_existing} || doc.selected_kanban == "Create New Board"`,
},
{
fieldtype: 'Data',
fieldname: 'board_name',
label: __('Kanban Board Name'),
mandatory_depends_on: 'eval: doc.selected_kanban == "Create New Board"',
description: ['Note', 'ToDo'].includes(doctype) ?
__('This Kanban Board will be private') : ''
}
];
if (doctype === 'Task') {
fields.push({
@ -282,7 +306,7 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown)
label: __('Columns based on'),
options: select_fields.map(df => ({label: df.label, value: df.fieldname})),
default: select_fields[0],
reqd: 1,
mandatory_depends_on: 'eval: doc.selected_kanban == "Create New Board"',
});
} else {
fields = [{
@ -302,9 +326,4 @@ frappe.views.KanbanView.setup_dropdown_in_sidebar = function(doctype, $dropdown)
return fields;
}
function get_kanban_boards() {
return frappe.call('frappe.desk.doctype.kanban_board.kanban_board.get_kanban_boards', { doctype })
.then(r => r.message);
}
};

File diff suppressed because it is too large Load diff

View file

@ -57,6 +57,12 @@
}
}
.control-label,
.grid-heading-row {
color: var(--grey-700);
font-size: 12px;
}
// .form-print-wrapper {
// border: 1px solid $border-color;
// border-top: none;

View file

@ -134,3 +134,8 @@ h2 {
padding: 4px 12px;
font-size: var(--text-md);
}
.input-xs {
height: 26px;
font-size: var(--text-md);
}

View file

@ -15,6 +15,11 @@
stroke: var(--grey-700);
}
.icon-xs {
width: 12px;
height: 12px;
}
.icon-sm {
width: 16px;
height: 16px;

View file

@ -1,3 +1,588 @@
.frappe-list {
.result, .no-result, .freeze {
min-height: #{"calc(100vh - 284px)"};
}
.msg-box {
margin-bottom: 8em;
// To compensate for percieved centering
.null-state {
height: 15rem !important;
max-height: 150px;
width: auto;
}
.meta-description {
width: 45%;
margin-right: auto;
margin-left: auto;
}
}
}
.freeze-row {
.level-left, .level-right, .list-row-col {
height: 100%;
width: 100%;
}
.list-row-col {
background-color: $border-color;
border-radius: 2px;
animation: 2s breathe infinite;
}
}
@keyframes breathe {
0% {
opacity: 0.2;
}
50% {
opacity: 0.5;
}
100% {
opacity: 0.2;
}
}
// body.no-list-sidebar {
// [data-page-route^="List/"] {
// @media (min-width: $screen-md) {
// .layout-side-section {
// display: none;
// }
// .layout-main-section-wrapper {
// width: 100% !important;
// }
// }
// }
// }
.filter-list {
position: relative;
.tag-filters-area {
padding: 10px 150px 0 10px;
}
.sort-selector {
position: absolute;
top: 0px;
right: 0px;
margin: 10px;
display: flex;
.dropdown:hover {
text-decoration: underline;
}
.dropdown-menu {
max-height: 300px;
overflow-y: scroll;
right: 0;
left: auto;
}
button {
margin-left: 10px;
}
}
}
.list-row-container {
border-bottom: 1px solid $border-color;
display: flex;
flex-direction: column;
outline: none;
// &:focus {
// background-color: $light-yellow;
// }
}
.list-row {
padding: 12px 15px;
height: 40px;
cursor: pointer;
transition: color 0.2s;
-webkit-transition: color 0.2s;
&:hover {
background-color: $gray-50;
}
&:last-child {
border-bottom: 0px;
}
.level-left {
flex: 3;
width: 75%;
}
.level-right {
flex: 1;
}
font-size: var(--text-md);
}
.list-row-activity {
justify-content: flex-end;
min-width: 120px;
.avatar:not(.avatar-empty) {
margin: 0;
}
&> span {
display: inline-block;
&:not(:last-child) {
margin-right: 8px;
}
}
.comment-count {
min-width: 35px;
}
}
}
.list-row-head {
.list-subject {
font-weight: normal;
}
.checkbox-actions {
display: none;
}
}
.list-row-col {
flex: 1;
margin-right: 15px;
}
.list-subject {
flex: 2;
justify-content: start;
.level-item {
margin-right: 8px;
}
&.seen {
font-weight: normal;
}
}
.list-paging-area, .footnote-area {
padding: 10px 15px;
border-top: 1px solid $border-color;
overflow: auto;
}
.progress {
height: 10px;
}
.likes-count {
display: none;
}
.list-liked-by-me {
margin-bottom: 1px;
}
input.list-check-all, input.list-row-checkbox {
margin-top: 0px;
}
.filterable {
cursor: pointer;
}
.listview-main-section {
.octicon-heart {
cursor: pointer;
}
.page-form {
padding-left: 17px;
// @media (max-width: $screen-sm) {
// padding-left: 25px;
// }
.octicon-search {
float: left;
padding-top: 7px;
margin-left: -4px;
margin-right: -4px;
// @media (max-width: $screen-sm) {
// margin-left: -12px;
// }
}
}
}
.modal-body {
.list-item--head {
position: sticky !important;
z-index: 500;
top: 0;
}
}
.list-items {
width: 100%;
}
.list-item-container {
border-bottom: 1px solid $border-color;
&:last-child {
border-bottom: none;
}
}
.list-item-table {
border: 1px solid $border-color;
border-radius: 3px;
}
.list-item {
display: flex;
align-items: center;
cursor: pointer;
height: 40px;
padding-left: 15px;
font-size: var(--text-md);
&:hover {
background-color: $gray-50;
}
// @media (max-width: $screen-xs) {
// height: 50px;
// padding-left: 10px;
// font-size: $text-regular;
// font-weight: normal;
// }
&--head {
background-color: $gray-50;
border-bottom: 1px solid $border-color;
cursor: auto;
}
input[type=checkbox] {
margin: 0;
margin-right: 5px;
flex: 0 0 12px;
}
.liked-by, .liked-by-filter-button {
display: inline-block;
width: 20px;
margin-right: 10px;
}
}
.list-item__content {
flex: 1;
margin-right: 15px;
display: flex;
align-items: center;
&--flex-2 {
flex: 2;
}
&--activity {
justify-content: flex-end;
margin-right: 5px;
min-width: 110px;
.list-row-modified, .avatar-small {
margin-right: 10px;
}
}
&--indicator span::before {
height: 12px;
width: 12px;
}
&--id {
justify-content: flex-end;
}
}
.frappe-timestamp {
white-space: nowrap;
}
// .like-action.octicon-heart {
// color: $heart-color;
// }
.list-comment-count {
display: inline-block;
width: 37px;
text-align: left;
}
// tags
.result.tags-shown {
.tag-row {
display: block;
}
}
.tag-row {
display: none;
margin-left: 50px;
}
.taggle_placeholder {
top: 0;
left: 5px;
font-size: 11px;
color: $text-muted;
}
.page-form {
.awesomplete > ul {
min-width: 300px;
}
}
.frappe-rtl {
.restricted-button {
margin: auto auto auto 5px;
direction: ltr;
}
}
// Image view
// .image-view-container {
// display: flex;
// flex-wrap: wrap;
// .image-view-row {
// display: flex;
// border-bottom: 1px solid #ebeff2;
// }
// .image-view-item {
// flex: 0 0 100%/4;
// padding: 15px;
// // border-bottom: 1px solid $light-border-color;
// // border-right: 1px solid $light-border-color;
// max-width: 100%/4;
// }
// .image-view-item:nth-child(4n) {
// border-right: none;
// }
// .image-view-header {
// margin-bottom: 10px;
// }
// .image-view-info {
// margin-top: 10px;
// }
// .image-view-body {
// &:hover .zoom-view {
// opacity: 0.7;
// }
// a {
// text-decoration: none;
// }
// }
// .image-field {
// display: flex;
// align-content: center;
// align-items: center;
// justify-content: center;
// position: relative;
// height: 200px;
// img {
// max-height: 100%;
// }
// // &.no-image {
// // background-color: $light-bg;
// // }
// }
// .placeholder-text {
// font-size: 72px;
// // color: $text-extra-muted;
// }
// .zoom-view {
// bottom: 10px !important;
// right: 10px !important;
// width: 36px;
// height: 36px;
// opacity: 0;
// font-size: 16px;
// color: $text-color;
// position: absolute;
// // // show zoom button on mobile devices
// // @media (max-width: $screen-xs) {
// // opacity: 0.5
// // }
// }
// // 3 columns for small screen
// // @media(max-width: $screen-sm) {
// // .image-view-container.three-column;
// // }
// }
// .item-selector {
// border: 1px solid $border-color;
// .image-view-row {
// width: 100%;
// }
// .image-field {
// height: 120px;
// }
// .placeholder-text {
// font-size: 48px;
// }
// }
// .image-view-container.three-column {
// .image-view-item {
// flex: 0 0 100%/3;
// max-width: 100%/3;
// }
// .image-view-item:nth-child(3n) {
// border-right: none;
// }
// .image-view-item:nth-last-child(-n + 3):nth-child(3n + 1),
// .image-view-item:nth-last-child(-n + 3):nth-child(3n + 1) ~ .image-view-item {
// border-bottom: none;
// }
// .image-view-item:nth-child(4n) {
// // border-right: 1px solid $light-border-color;
// }
// .image-view-item:nth-last-child(-n + 4):nth-child(4n + 1),
// .image-view-item:nth-last-child(-n + 4):nth-child(4n + 1) ~ .image-view-item {
// border-bottom: 1px solid $light-border-color;
// }
// }
// .pswp--svg .pswp__button,
// .pswp--svg .pswp__button--arrow--left:before,
// .pswp--svg .pswp__button--arrow--right:before {
// background-image: url('/assets/frappe/images/default-skin.svg') !important;
// }
// .pswp--svg .pswp__button--arrow--left,
// .pswp--svg .pswp__button--arrow--right {
// background: none !important;
// }
// .pswp__bg {
// background-color: #fff !important;
// }
// .pswp__more-items {
// position: absolute;
// bottom: 12px;
// left: 50%;
// transform: translateX(-50%);
// }
// .pswp__more-item {
// display: inline-block;
// margin: 5px;
// height: 100px;
// cursor: pointer;
// border: 1px solid $border-color;
// img {
// max-height: 100%;
// }
// }
// gantt
// .list-paging-area .gantt-view-mode {
// margin-left: 15px;
// margin-right: 15px;
// }
// .gantt {
// .details-container {
// .heading {
// margin-bottom: 10px;
// font-size: 12px;
// }
// .avatar-small {
// width: 16px;
// height: 16px;
// }
// .standard-image {
// display: block;
// }
// }
// }
// .inbox-attachment, .inbox-link {
// margin-right: 7px;
// }
// .select-inbox {
// padding: 30px 30px;
// }
// .inbox-value {
// padding-top: 2px;
// }
// list view
// .file-grid {
// display: flex;
// flex-wrap: wrap;
// align-content: flex-start;
// a {
// height: 100%;
// }
// }
// .file-wrapper {
// width: 120px;
// flex-direction: column;
// align-items: center;
// }
// .file-title {
// margin-top: 5px;
// }

View file

@ -14,6 +14,7 @@
@import "desktop";
@import "awesomebar";
@import "sidebar";
@import "list";
@import "frappe/public/css/font-awesome";
@import "multilevel-dropdown";

View file

@ -19,6 +19,9 @@
padding: 4px 20px;
font-size: var(--text-md);
}
.custom-btn-group .btn {
padding: 4px 15px;
}
}
.page-form {
@ -120,13 +123,13 @@
// margin-top: 70px;
// }
// /* show menu aligned to the right border of the dropdown */
// .page-actions .dropdown-menu,
// .form-inner-toolbar .dropdown-menu {
// right: 0px;
// left: auto;
// z-index: 100;
// }
/* show menu aligned to the right border of the dropdown */
.page-actions .dropdown-menu,
.form-inner-toolbar .dropdown-menu {
right: 0px;
left: auto;
z-index: 100;
}
// .layout-footer {
// border: 1px solid @border-color;
@ -419,12 +422,12 @@
// align-items: center;
// }
// .menu-btn-group {
// .dropdown-menu {
// width: max-content;
// }
.menu-btn-group, .custom-btn-group {
.dropdown-menu {
width: max-content;
}
// .menu-item-label {
// margin-right: 15px;
// }
// }
.menu-item-label {
margin-right: 15px;
}
}

View file

@ -65,13 +65,13 @@ body[data-route^="Module"] .main-menu {
}
.sidebar-menu {
.badge {
position: absolute;
font-weight: normal;
right: 0px;
top: 0px;
padding-bottom: 4px;
}
// .badge {
// position: absolute;
// font-weight: normal;
// right: 0px;
// top: 0px;
// padding-bottom: 4px;
// }
.octicon {
font-size: 12px;
@ -85,10 +85,6 @@ body[data-route^="Module"] .main-menu {
> li {
position: relative;
}
.list-link {
margin: 7px 0px;
}
}
// form sidebar
@ -367,22 +363,54 @@ body[data-route^="Module"] .main-menu {
.list-sidebar {
.sidebar-section {
margin-bottom: 30px;
}
.list-link {
margin-top: 20px;
}
.list-sidebar-label {
color: $text-muted;
color: var(--grey-600);
text-transform: uppercase;
margin-bottom: 0;
font-size: var(--text-sm);
font-size: var(--text-xs);
font-weight: 600;
}
.list-sidebar-button {
display: flex;
justify-content: space-between;
padding: 4px 8px;
}
.group-by-count {
position:relative
}
.group-by-dropdown, .list-stats-dropdown {
.group-by-value {
width: 90%;
}
.dropdown-menu {
max-height: 300px;
overflow-y: auto;
min-width: 180px;
max-width: 250px;
z-index: 100;
.dropdown-item {
display: flex;
justify-content: space-between;
}
.empty-state {
padding: 10px 15px;
text-align: center;
color: $text-muted;
}
}
.dropdown-search {
@ -392,6 +420,12 @@ body[data-route^="Module"] .main-menu {
.stat-no-records {
margin: 5px 10px;
}
.sidebar-action {
font-size: var(--text-sm);
color: var(--primary);
margin-top: 10px;
}
}
.filters-search {