fix: refactor report group by
This commit is contained in:
parent
a777244ac0
commit
de8a3cd2d6
4 changed files with 452 additions and 136 deletions
|
|
@ -1,48 +1,48 @@
|
|||
<div class="groupby-box" style="display: none">
|
||||
<div class="group-by-box">
|
||||
<div class="list_groupby row">
|
||||
<div class="col-sm-4 form-group ui-front">
|
||||
<select class="groupby form-control">
|
||||
<div class="col-sm-8 form-group">
|
||||
<select class="group-by form-control input-xs">
|
||||
<option value="" disabled selected>{{ __("Select Group By...") }}</option>
|
||||
{% for (var parent_doctype in groupby_conditions) { %}
|
||||
{% for (var val in groupby_conditions[parent_doctype]) { %}
|
||||
{% for (var parent_doctype in group_by_conditions) { %}
|
||||
{% for (var val in group_by_conditions[parent_doctype]) { %}
|
||||
{% if (parent_doctype !== doctype) { %}
|
||||
<option
|
||||
<option
|
||||
data-doctype="{{parent_doctype}}"
|
||||
value="{{groupby_conditions[parent_doctype][val].fieldname}}">
|
||||
{{ groupby_conditions[parent_doctype][val].label }}
|
||||
value="{{group_by_conditions[parent_doctype][val].fieldname}}"
|
||||
>
|
||||
{{ group_by_conditions[parent_doctype][val].label }}
|
||||
({{ parent_doctype }})
|
||||
</option>
|
||||
{% } else { %}
|
||||
<option
|
||||
<option
|
||||
data-doctype="{{parent_doctype}}"
|
||||
value="{{groupby_conditions[parent_doctype][val].fieldname}}">
|
||||
{{ groupby_conditions[parent_doctype][val].label }}
|
||||
value="{{group_by_conditions[parent_doctype][val].fieldname}}"
|
||||
>
|
||||
{{ group_by_conditions[parent_doctype][val].label }}
|
||||
</option>
|
||||
{% } %}
|
||||
{% } %}
|
||||
{% } %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-2 form-group">
|
||||
<select class="aggregate-function form-control">
|
||||
<div class="col-sm-3 form-group">
|
||||
<select class="aggregate-function form-control input-xs">
|
||||
{% for condition in aggregate_function_conditions %}
|
||||
<option value="{{condition.name}}">{{ condition.label }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-6 col-xs-12">
|
||||
<div class="groupby-field pull-left">
|
||||
<select class="aggregate-on form-control" style="display: none">
|
||||
<option value="" disabled selected>{{ __("Select Field...") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="groupby-actions pull-left">
|
||||
<a class="small grey remove-groupby pull-left">
|
||||
<i class="octicon octicon-trashcan visible-xs"></i>
|
||||
<span class="hidden-xs">{{ __("Remove") }}</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="col-sm-4 col-xs-12" style="display: none">
|
||||
<select class="aggregate-on form-control input-xs">
|
||||
<option value="" disabled selected>{{ __("Select Field...") }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="groupby-actions pull-left col-sm-1">
|
||||
<span class="remove-group-by">
|
||||
<svg class="icon icon-sm">
|
||||
<use xlink:href="#icon-close"></use>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
frappe.provide('frappe.views');
|
||||
|
||||
frappe.ui.GroupBy = class {
|
||||
|
|
@ -6,85 +5,182 @@ frappe.ui.GroupBy = class {
|
|||
this.report_view = report_view;
|
||||
this.page = report_view.page;
|
||||
this.doctype = report_view.doctype;
|
||||
this.setup_group_by_area();
|
||||
this.make();
|
||||
}
|
||||
|
||||
make() {
|
||||
this.make_group_by_button();
|
||||
this.init_group_by_popover();
|
||||
this.set_popover_events();
|
||||
}
|
||||
|
||||
init_group_by_popover() {
|
||||
const sql_aggregate_functions = [
|
||||
{ name: 'count', label: 'Count' },
|
||||
{ name: 'sum', label: 'Sum' },
|
||||
{ name: 'avg', label: 'Average' },
|
||||
];
|
||||
|
||||
const group_by_template = $(
|
||||
frappe.render_template('group_by', {
|
||||
doctype: this.doctype,
|
||||
group_by_conditions: this.get_group_by_fields(),
|
||||
aggregate_function_conditions: sql_aggregate_functions,
|
||||
})
|
||||
);
|
||||
|
||||
this.group_by_button.popover({
|
||||
content: group_by_template,
|
||||
template: `
|
||||
<div class="group-by-popover popover">
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-body popover-content">
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
html: true,
|
||||
trigger: 'manual',
|
||||
container: 'body',
|
||||
placement: 'bottom',
|
||||
offset: '-100px 0',
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: make common with filter popover
|
||||
set_popover_events() {
|
||||
$(document.body).on('click', (e) => {
|
||||
if (this.wrapper && this.wrapper.is(':visible')) {
|
||||
if (
|
||||
$(e.target).parents('.group-by-popover').length === 0 &&
|
||||
$(e.target).parents('.group-by-box').length === 0 &&
|
||||
$(e.target).parents('.group-by-button').length === 0 &&
|
||||
!$(e.target).is(this.group_by_button)
|
||||
) {
|
||||
this.wrapper && this.group_by_button.popover('hide');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.group_by_button.on('click', () => {
|
||||
this.group_by_button.popover('toggle');
|
||||
});
|
||||
|
||||
this.group_by_button.on('shown.bs.popover', (e) => {
|
||||
if (!this.wrapper) {
|
||||
this.wrapper = $('.group-by-popover');
|
||||
this.setup_group_by_area();
|
||||
}
|
||||
});
|
||||
|
||||
this.group_by_button.on('hidden.bs.popover', (e) => {
|
||||
this.update_group_by_button();
|
||||
});
|
||||
|
||||
$(window).on('hashchange', () => {
|
||||
this.group_by_button.popover('hide');
|
||||
});
|
||||
}
|
||||
|
||||
setup_group_by_area() {
|
||||
this.make_group_by_button();
|
||||
let sql_aggregate_function = [
|
||||
{name:'count', label: 'Count'},
|
||||
{name:'sum', label: 'Sum'},
|
||||
{name:'avg', label:'Average'}
|
||||
];
|
||||
this.groupby_edit_area = $(frappe.render_template("group_by", {
|
||||
doctype: this.doctype,
|
||||
groupby_conditions: this.get_group_by_fields(),
|
||||
aggregate_function_conditions: sql_aggregate_function,
|
||||
}));
|
||||
|
||||
this.groupby_select = this.groupby_edit_area.find('select.groupby');
|
||||
this.aggregate_function_select = this.groupby_edit_area.find('select.aggregate-function');
|
||||
this.aggregate_on_select = this.groupby_edit_area.find('select.aggregate-on');
|
||||
this.aggregate_on_html = ``;
|
||||
// set default to count
|
||||
this.aggregate_function_select.val("count");
|
||||
this.page.wrapper.find(".frappe-list").append(
|
||||
this.groupby_edit_area);
|
||||
this.group_by_select = this.wrapper.find('select.group-by');
|
||||
this.group_by_field && this.group_by_select.val(this.group_by_field);
|
||||
this.aggregate_function_select = this.wrapper.find(
|
||||
'select.aggregate-function'
|
||||
);
|
||||
this.aggregate_on_select = this.wrapper.find('select.aggregate-on');
|
||||
this.remove_group_by_button = this.wrapper.find('.remove-group-by');
|
||||
|
||||
//Set aggregate on options as numeric fields if function is sum or average
|
||||
this.aggregate_function_select.on('change', () => {
|
||||
this.show_hide_aggregate_on();
|
||||
});
|
||||
if (this.aggregate_function) {
|
||||
this.aggregate_function_select.val(this.aggregate_function);
|
||||
} else {
|
||||
// set default to count
|
||||
this.aggregate_function_select.val('count');
|
||||
this.aggregate_function = 'count';
|
||||
}
|
||||
|
||||
this.toggle_aggregate_on_field();
|
||||
this.aggregate_on && this.aggregate_on_select.val(this.aggregate_on_field);
|
||||
|
||||
this.set_group_by_events();
|
||||
}
|
||||
|
||||
set_group_by_events() {
|
||||
// try running on change
|
||||
this.groupby_select.on('change', () => this.apply_group_by_and_refresh());
|
||||
this.aggregate_function_select.on('change', () => this.apply_group_by_and_refresh());
|
||||
this.aggregate_on_select.on('change', () => this.apply_group_by_and_refresh());
|
||||
|
||||
$('.set-groupby-and-run').on('click', () => {
|
||||
this.group_by_select.on('change', () => {
|
||||
this.group_by_field = this.group_by_select.val();
|
||||
this.group_by_doctype = this.group_by_select
|
||||
.find(':selected')
|
||||
.attr('data-doctype');
|
||||
this.apply_group_by_and_refresh();
|
||||
});
|
||||
|
||||
$('.remove-groupby').on('click', () => {
|
||||
this.aggregate_function_select.on('change', () => {
|
||||
//Set aggregate on options as numeric fields if function is sum or average
|
||||
this.toggle_aggregate_on_field();
|
||||
this.aggregate_function = this.aggregate_function_select.val();
|
||||
this.apply_group_by_and_refresh();
|
||||
});
|
||||
|
||||
this.aggregate_on_select.on('change', () => {
|
||||
this.aggregate_on_field = this.aggregate_on_select.val();
|
||||
this.aggregate_on_doctype = this.aggregate_on_select
|
||||
.find(':selected')
|
||||
.attr('data-doctype');
|
||||
this.apply_group_by_and_refresh();
|
||||
});
|
||||
|
||||
this.remove_group_by_button.on('click', () => {
|
||||
this.remove_group_by();
|
||||
});
|
||||
}
|
||||
|
||||
show_hide_aggregate_on() {
|
||||
toggle_aggregate_on_field() {
|
||||
let fn = this.aggregate_function_select.val();
|
||||
if (fn === 'sum' || fn === 'avg') {
|
||||
if (!this.aggregate_on_html.length) {
|
||||
this.aggregate_on_html = `<option value="" disabled selected>
|
||||
${__("Select Field...")}</option>`;
|
||||
${__('Select Field...')}
|
||||
</option>`;
|
||||
|
||||
for (let doctype in this.all_fields) {
|
||||
const doctype_fields = this.all_fields[doctype];
|
||||
doctype_fields.forEach(field => {
|
||||
doctype_fields.forEach((field) => {
|
||||
// pick numeric fields for sum / avg
|
||||
if (frappe.model.is_numeric_field(field.fieldtype)) {
|
||||
let option_text = doctype == this.doctype
|
||||
? field.label
|
||||
: `${field.label} (${doctype})`;
|
||||
this.aggregate_on_html+= `<option data-doctype="${doctype}"
|
||||
let option_text =
|
||||
doctype == this.doctype
|
||||
? field.label
|
||||
: `${field.label} (${doctype})`;
|
||||
this.aggregate_on_html += `<option data-doctype="${doctype}"
|
||||
value="${field.fieldname}">${option_text}</option>`;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
this.aggregate_on_select.html(this.aggregate_on_html);
|
||||
this.aggregate_on_select.show();
|
||||
this.toggle_aggregate_on_field_display(true);
|
||||
} else {
|
||||
// count, so no aggregate function
|
||||
this.aggregate_on_select.hide();
|
||||
this.toggle_aggregate_on_field_display(false);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Fix this
|
||||
toggle_aggregate_on_field_display(show) {
|
||||
this.group_by_select.parent().toggleClass('col-sm-5', show);
|
||||
this.group_by_select.parent().toggleClass('col-sm-8', !show);
|
||||
this.aggregate_function_select.parent().toggleClass('col-sm-2', show);
|
||||
this.aggregate_function_select.parent().toggleClass('col-sm-3', !show);
|
||||
this.aggregate_on_select.parent().toggle(show);
|
||||
}
|
||||
|
||||
get_settings() {
|
||||
if (this.group_by) {
|
||||
if (this.group_by) {
|
||||
return {
|
||||
group_by: this.group_by,
|
||||
aggregate_function: this.aggregate_function,
|
||||
aggregate_on: this.aggregate_on
|
||||
aggregate_on: this.aggregate_on,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
|
|
@ -92,70 +188,93 @@ frappe.ui.GroupBy = class {
|
|||
}
|
||||
|
||||
apply_settings(settings) {
|
||||
let get_fieldname = (name) => name.split('.')[1].replace(/`/g, '');
|
||||
let get_doctype = (name) =>
|
||||
name
|
||||
.split('.')[0]
|
||||
.replace(/`/g, '')
|
||||
.replace('tab', '');
|
||||
|
||||
if (!settings.group_by.startsWith('`tab')) {
|
||||
settings.group_by = '`tab' + this.doctype + '`.`' + settings.group_by + '`';
|
||||
settings.group_by =
|
||||
'`tab' + this.doctype + '`.`' + settings.group_by + '`';
|
||||
}
|
||||
|
||||
if (settings.aggregate_on && !settings.aggregate_on.startsWith('`tab')) {
|
||||
const aggregate_on_doctype = this.get_aggregate_on_doctype(settings);
|
||||
settings.aggregate_on =
|
||||
'`tab' + aggregate_on_doctype + '`.`' + settings.aggregate_on + '`';
|
||||
}
|
||||
|
||||
// Extract fieldname from `tabdoctype`.`fieldname`
|
||||
let group_by_fieldname = settings.group_by.split('.')[1].replace(/`/g, '');
|
||||
this.group_by_field = get_fieldname(settings.group_by);
|
||||
this.group_by_doctype = get_doctype(settings.group_by);
|
||||
|
||||
this.groupby_select.val(group_by_fieldname);
|
||||
this.aggregate_function_select.val(settings.aggregate_function);
|
||||
this.show_hide_aggregate_on();
|
||||
this.aggregate_on_select.val(settings.aggregate_on);
|
||||
this.groupby_edit_area.show();
|
||||
this.aggregate_function = settings.aggregate_function;
|
||||
|
||||
if (settings.aggregate_on) {
|
||||
this.aggregate_on_field = get_fieldname(settings.aggregate_on);
|
||||
this.aggregate_on_doctype = get_doctype(settings.aggregate_on);
|
||||
}
|
||||
|
||||
this.apply_group_by();
|
||||
this.update_group_by_button();
|
||||
}
|
||||
|
||||
get_aggregate_on_doctype(settings) {
|
||||
for (let doctype of Object.keys(this.all_fields)) {
|
||||
const dt_fields = this.all_fields[doctype];
|
||||
if (dt_fields.find((field) => field.fieldname == settings.aggregate_on)) {
|
||||
return doctype;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
make_group_by_button() {
|
||||
this.group_by_button = $(`<div class="tag-groupby-area">
|
||||
<div class="active-tag-groupby">
|
||||
<button class="btn btn-default btn-xs add-groupby text-muted">
|
||||
${__("Add Group")}
|
||||
this.page.wrapper.find('.sort-selector').before(
|
||||
$(`<div class="group-by-selector">
|
||||
<button class="btn btn-default btn-xs group-by-button ellipsis">
|
||||
<span class="group-by-icon">
|
||||
<svg class="icon icon-sm">
|
||||
<use xlink:href="#icon-group-by"></use>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="button-label">
|
||||
${__('Add Group')}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>`);
|
||||
this.page.wrapper.find(".sort-selector").before(this.group_by_button);
|
||||
this.group_by_button.click(() => {
|
||||
this.toggle_group_by_area(true);
|
||||
});
|
||||
}
|
||||
</div>`)
|
||||
);
|
||||
|
||||
toggle_group_by_area(show) {
|
||||
this.groupby_edit_area.toggle(show);
|
||||
this.group_by_button.toggle(!show);
|
||||
this.group_by_button = this.page.wrapper.find('.group-by-button');
|
||||
}
|
||||
|
||||
apply_group_by() {
|
||||
this.group_by_doctype = this.groupby_select.find(':selected').attr('data-doctype');
|
||||
this.group_by_field = this.groupby_select.val();
|
||||
this.group_by = '`tab' + this.group_by_doctype + '`.`' + this.group_by_field + '`';
|
||||
this.aggregate_function = this.aggregate_function_select.val();
|
||||
this.group_by =
|
||||
'`tab' + this.group_by_doctype + '`.`' + this.group_by_field + '`';
|
||||
|
||||
if (this.aggregate_function === 'count') {
|
||||
this.aggregate_on = 'name';
|
||||
this.aggregate_on_field = null;
|
||||
this.aggregate_on_doctype = null;
|
||||
} else {
|
||||
this.aggregate_on = this.aggregate_on_select.val();
|
||||
this.aggregate_on_doctype = this.aggregate_on_select.find(':selected').attr('data-doctype');
|
||||
this.aggregate_on =
|
||||
'`tab' +
|
||||
this.aggregate_on_doctype +
|
||||
'`.`' +
|
||||
this.aggregate_on_field +
|
||||
'`';
|
||||
}
|
||||
|
||||
|
||||
//All necessary fields must be set before applying group by
|
||||
if(!this.group_by) {
|
||||
this.page.wrapper.find('.groupby').focus();
|
||||
return;
|
||||
} else if(!this.aggregate_function) {
|
||||
this.page.wrapper.find('.aggregate-function').focus();
|
||||
return;
|
||||
} else if(!this.aggregate_on && this.aggregate_function!=='count') {
|
||||
this.page.wrapper.find('.aggregate-on').focus();
|
||||
return;
|
||||
if (
|
||||
!this.group_by ||
|
||||
!this.aggregate_function ||
|
||||
(!this.aggregate_on_field && this.aggregate_function !== 'count')
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
apply_group_by_and_refresh() {
|
||||
|
|
@ -167,32 +286,35 @@ frappe.ui.GroupBy = class {
|
|||
set_args(args) {
|
||||
if (this.aggregate_function && this.group_by) {
|
||||
let aggregate_column, aggregate_on_field;
|
||||
|
||||
if (this.aggregate_function === 'count') {
|
||||
aggregate_column = 'count(`tab'+ this.doctype + '`.`name`)';
|
||||
aggregate_column = 'count(`tab' + this.doctype + '`.`name`)';
|
||||
} else {
|
||||
aggregate_column =
|
||||
`${this.aggregate_function}(\`tab${this.aggregate_on_doctype}\`.\`${this.aggregate_on}\`)`;
|
||||
aggregate_on_field = '`tab' + this.aggregate_on_doctype + '`.`' + this.aggregate_on + '`';
|
||||
aggregate_column = `${this.aggregate_function}(${this.aggregate_on})`;
|
||||
aggregate_on_field = this.aggregate_on;
|
||||
}
|
||||
|
||||
this.report_view.group_by = this.group_by;
|
||||
this.report_view.sort_by = '_aggregate_column';
|
||||
this.report_view.sort_order = 'desc';
|
||||
|
||||
// save orignial fields
|
||||
if(!this.report_view.fields.map(f => f[0]).includes('_aggregate_column')) {
|
||||
this.original_fields = this.report_view.fields.map(f => f);
|
||||
// save original fields
|
||||
if (
|
||||
!this.report_view.fields.map((f) => f[0]).includes('_aggregate_column')
|
||||
) {
|
||||
this.original_fields = this.report_view.fields.map((f) => f);
|
||||
}
|
||||
|
||||
this.report_view.fields = [
|
||||
[this.group_by_field, this.group_by_doctype]
|
||||
];
|
||||
this.report_view.fields = [[this.group_by_field, this.group_by_doctype]];
|
||||
|
||||
// rebuild fields for group by
|
||||
args.fields = this.report_view.get_fields();
|
||||
|
||||
// add aggregate column in both query args and report views
|
||||
this.report_view.fields.push(['_aggregate_column', this.aggregate_on_doctype || this.doctype]);
|
||||
this.report_view.fields.push([
|
||||
'_aggregate_column',
|
||||
this.aggregate_on_doctype || this.doctype,
|
||||
]);
|
||||
args.fields.push(aggregate_column + ' as _aggregate_column');
|
||||
|
||||
if (aggregate_on_field) {
|
||||
|
|
@ -205,48 +327,53 @@ frappe.ui.GroupBy = class {
|
|||
Object.assign(args, {
|
||||
with_comment_count: false,
|
||||
group_by: this.report_view.group_by || null,
|
||||
order_by: '_aggregate_column desc'
|
||||
order_by: '_aggregate_column desc',
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
get_group_by_docfield() {
|
||||
// called from build_column
|
||||
let docfield;
|
||||
let docfield = {};
|
||||
if (this.aggregate_function === 'count') {
|
||||
docfield = {
|
||||
fieldtype: 'Int',
|
||||
label: __('Count'),
|
||||
parent: this.doctype,
|
||||
width: 120
|
||||
width: 200,
|
||||
};
|
||||
} else {
|
||||
// get properties of "aggregate_on", for example Net Total
|
||||
docfield = Object.assign({}, frappe.meta.docfield_map[this.aggregate_on_doctype][this.aggregate_on]);
|
||||
docfield = Object.assign(
|
||||
{},
|
||||
frappe.meta.docfield_map[this.aggregate_on_doctype][
|
||||
this.aggregate_on_field
|
||||
]
|
||||
);
|
||||
|
||||
if (this.aggregate_function === 'sum') {
|
||||
docfield.label = __('Sum of {0}', [docfield.label]);
|
||||
} else {
|
||||
docfield.label = __('Average of {0}', [docfield.label]);
|
||||
}
|
||||
}
|
||||
docfield.fieldname = '_aggregate_column';
|
||||
|
||||
docfield.fieldname = '_aggregate_column';
|
||||
return docfield;
|
||||
}
|
||||
|
||||
remove_group_by() {
|
||||
this.toggle_group_by_area(false);
|
||||
|
||||
this.order_by = '';
|
||||
this.group_by = null;
|
||||
this.group_by_field = null;
|
||||
this.report_view.group_by = null;
|
||||
this.aggregate_function = null;
|
||||
this.aggregate_on = null;
|
||||
$(".groupby").val("");
|
||||
$(".aggregate-function").val("count");
|
||||
$(".aggregate-on").empty().val("").hide();
|
||||
this.aggregate_on_field = null;
|
||||
this.group_by_select.val('');
|
||||
this.aggregate_function_select.val('count');
|
||||
this.aggregate_on_select.empty().val('');
|
||||
this.aggregate_on_select.parent().hide();
|
||||
|
||||
// restore original fields
|
||||
if (this.original_fields) {
|
||||
|
|
@ -263,23 +390,51 @@ frappe.ui.GroupBy = class {
|
|||
this.group_by_fields = {};
|
||||
this.all_fields = {};
|
||||
|
||||
let fields = this.report_view.meta.fields.filter(f => ["Select", "Link", "Data", "Int", "Check"].includes(f.fieldtype));
|
||||
let fields = this.report_view.meta.fields.filter((f) =>
|
||||
['Select', 'Link', 'Data', 'Int', 'Check'].includes(f.fieldtype)
|
||||
);
|
||||
this.group_by_fields[this.doctype] = fields;
|
||||
this.all_fields[this.doctype] = this.report_view.meta.fields;
|
||||
|
||||
const standard_fields_filter = df =>
|
||||
const standard_fields_filter = (df) =>
|
||||
!in_list(frappe.model.no_value_type, df.fieldtype) && !df.report_hide;
|
||||
|
||||
const table_fields = frappe.meta.get_table_fields(this.doctype)
|
||||
.filter(df => !df.hidden);
|
||||
const table_fields = frappe.meta
|
||||
.get_table_fields(this.doctype)
|
||||
.filter((df) => !df.hidden);
|
||||
|
||||
table_fields.forEach(df => {
|
||||
table_fields.forEach((df) => {
|
||||
const cdt = df.options;
|
||||
const child_table_fields = frappe.meta.get_docfields(cdt).filter(standard_fields_filter);
|
||||
const child_table_fields = frappe.meta
|
||||
.get_docfields(cdt)
|
||||
.filter(standard_fields_filter);
|
||||
this.group_by_fields[cdt] = child_table_fields;
|
||||
this.all_fields[cdt] = child_table_fields;
|
||||
});
|
||||
|
||||
return this.group_by_fields;
|
||||
}
|
||||
|
||||
update_group_by_button() {
|
||||
const group_by_applied = Boolean(this.group_by_field);
|
||||
const button_label = group_by_applied
|
||||
? __(`Group By {0}`, [this.get_group_by_field_label()])
|
||||
: __('Add Group');
|
||||
|
||||
this.group_by_button
|
||||
.toggleClass('btn-default', !group_by_applied)
|
||||
.toggleClass('btn-active-blue', group_by_applied);
|
||||
|
||||
this.group_by_button.find('.group-by-icon')
|
||||
.toggleClass('active', group_by_applied);
|
||||
|
||||
this.group_by_button.find('.button-label').html(button_label);
|
||||
this.group_by_button.attr('title', button_label);
|
||||
}
|
||||
|
||||
get_group_by_field_label() {
|
||||
return this.group_by_fields[this.group_by_doctype].find(
|
||||
field => field.fieldname == this.group_by_field
|
||||
).label;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
157
frappe/public/scss/report.scss
Normal file
157
frappe/public/scss/report.scss
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
// grid report
|
||||
.grid-report .plot {
|
||||
margin: 15px;
|
||||
display: none;
|
||||
height: 300px !important;
|
||||
width: 97% !important;
|
||||
}
|
||||
|
||||
.grid-report .ui-widget {
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
border-top: 1px solid $border-color !important;
|
||||
// background-color: @light-bg !important;
|
||||
}
|
||||
|
||||
.grid-report .show-zero {
|
||||
margin: 10px;
|
||||
display: none
|
||||
}
|
||||
|
||||
// column picker
|
||||
.column-picker-dialog {
|
||||
.column-list {
|
||||
margin: 15px 0;
|
||||
border: 1px solid $border-color;
|
||||
|
||||
.column-list-item {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.column-list-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.sortable-handle {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
// .sortable-chosen {
|
||||
// background-color: @light-yellow;
|
||||
// }
|
||||
|
||||
.fa-sort {
|
||||
margin: 0px 7px;
|
||||
margin-top: 9px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
display: inline-block;
|
||||
width: 89%;
|
||||
|
||||
@include media-breakpoint-down(xs) {
|
||||
width: 77%;
|
||||
}
|
||||
}
|
||||
|
||||
.close {
|
||||
margin: 2px 7px 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.columns-search {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.report-wrapper {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.group-by-button {
|
||||
margin: 5px;
|
||||
padding: 4px 8px;
|
||||
max-width: 125px;
|
||||
}
|
||||
|
||||
.group-by-icon.active {
|
||||
use {
|
||||
stroke: var(--blue-500);
|
||||
}
|
||||
}
|
||||
|
||||
.group-by-popover {
|
||||
min-width: 500px;
|
||||
min-height: 50px;
|
||||
font-size: var(--text-md);
|
||||
|
||||
.group-by-box {
|
||||
padding: 5px 15px 5px 0;
|
||||
|
||||
.remove-group-by {
|
||||
line-height: 2em;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.report-summary {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
||||
grid-auto-rows: minmax(62px, 1fr);
|
||||
column-gap: 15px;
|
||||
row-gap: 20px;
|
||||
align-items: center;
|
||||
|
||||
padding: 15px 15px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
margin-right: 0px;
|
||||
margin-left: 0px;
|
||||
|
||||
.summary-label {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
|
||||
.summary-value {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 5px;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-feature-settings: "tnum";
|
||||
|
||||
div {
|
||||
text-align: left !important;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for sm and above
|
||||
@include media-breakpoint-up(xs) {
|
||||
.group-by-box .row > div[class*="col-sm-"] {
|
||||
padding-right: 0px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.frappe-control {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
// Enable tnum for report
|
||||
.dt-scrollable .dt-cell__content {
|
||||
font-feature-settings: "tnum", "zero";
|
||||
}
|
||||
|
|
@ -212,6 +212,10 @@
|
|||
<symbol viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" id="icon-filter">
|
||||
<path d="M2 4h12M4 8h8m-5.5 4h3" stroke-miterlimit="10" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-group-by">
|
||||
<rect x="2.5" y="3.5" width="11" height="3" rx="1.5"></rect>
|
||||
<rect x="2.5" y="9.5" width="9" height="3" rx="1.5"></rect>
|
||||
</symbol>
|
||||
<symbol viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" id="icon-external-link">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.348 3.207a1 1 0 0 1 1.415 0l1.03 1.03a1 1 0 0 1 0 1.415l-6.626 6.626L2.5 13.5l1.222-3.667 6.626-6.626z" stroke="#12283A" stroke-linecap="round" stroke-linejoin="round"></path>
|
||||
</symbol>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue