@@ -0,0 +1,59 @@ | |||||
export default { | |||||
name: "Child Table Doctype 1", | |||||
actions: [], | |||||
custom: 1, | |||||
autoname: "format: Test-{####}", | |||||
creation: "2022-02-09 20:15:21.242213", | |||||
doctype: "DocType", | |||||
editable_grid: 1, | |||||
engine: "InnoDB", | |||||
fields: [ | |||||
{ | |||||
fieldname: "data", | |||||
fieldtype: "Data", | |||||
in_list_view: 1, | |||||
label: "Data" | |||||
}, | |||||
{ | |||||
fieldname: "barcode", | |||||
fieldtype: "Barcode", | |||||
in_list_view: 1, | |||||
label: "Barcode" | |||||
}, | |||||
{ | |||||
fieldname: "check", | |||||
fieldtype: "Check", | |||||
in_list_view: 1, | |||||
label: "Check" | |||||
}, | |||||
{ | |||||
fieldname: "rating", | |||||
fieldtype: "Rating", | |||||
in_list_view: 1, | |||||
label: "Rating" | |||||
}, | |||||
{ | |||||
fieldname: "duration", | |||||
fieldtype: "Duration", | |||||
in_list_view: 1, | |||||
label: "Duration" | |||||
}, | |||||
{ | |||||
fieldname: "date", | |||||
fieldtype: "Date", | |||||
in_list_view: 1, | |||||
label: "Date" | |||||
} | |||||
], | |||||
links: [], | |||||
istable: 1, | |||||
modified: "2022-02-10 12:03:12.603763", | |||||
modified_by: "Administrator", | |||||
module: "Custom", | |||||
naming_rule: "By fieldname", | |||||
owner: "Administrator", | |||||
permissions: [], | |||||
sort_field: 'modified', | |||||
sort_order: 'ASC', | |||||
track_changes: 1 | |||||
}; |
@@ -20,6 +20,12 @@ export default { | |||||
label: "Child Table", | label: "Child Table", | ||||
options: "Child Table Doctype", | options: "Child Table Doctype", | ||||
reqd: 1 | reqd: 1 | ||||
}, | |||||
{ | |||||
fieldname: "child_table_1", | |||||
fieldtype: "Table", | |||||
label: "Child Table 1", | |||||
options: "Child Table Doctype 1" | |||||
} | } | ||||
], | ], | ||||
links: [], | links: [], | ||||
@@ -1,5 +1,6 @@ | |||||
import doctype_with_child_table from '../fixtures/doctype_with_child_table'; | import doctype_with_child_table from '../fixtures/doctype_with_child_table'; | ||||
import child_table_doctype from '../fixtures/child_table_doctype'; | import child_table_doctype from '../fixtures/child_table_doctype'; | ||||
import child_table_doctype_1 from '../fixtures/child_table_doctype_1'; | |||||
import doctype_to_link from '../fixtures/doctype_to_link'; | import doctype_to_link from '../fixtures/doctype_to_link'; | ||||
const doctype_to_link_name = doctype_to_link.name; | const doctype_to_link_name = doctype_to_link.name; | ||||
const child_table_doctype_name = child_table_doctype.name; | const child_table_doctype_name = child_table_doctype.name; | ||||
@@ -9,6 +10,7 @@ context('Dashboard links', () => { | |||||
cy.visit('/login'); | cy.visit('/login'); | ||||
cy.login(); | cy.login(); | ||||
cy.insert_doc('DocType', child_table_doctype, true); | cy.insert_doc('DocType', child_table_doctype, true); | ||||
cy.insert_doc('DocType', child_table_doctype_1, true); | |||||
cy.insert_doc('DocType', doctype_with_child_table, true); | cy.insert_doc('DocType', doctype_with_child_table, true); | ||||
cy.insert_doc('DocType', doctype_to_link, true); | cy.insert_doc('DocType', doctype_to_link, true); | ||||
return cy.window().its('frappe').then(frappe => { | return cy.window().its('frappe').then(frappe => { | ||||
@@ -0,0 +1,107 @@ | |||||
import doctype_with_child_table from '../fixtures/doctype_with_child_table'; | |||||
import child_table_doctype from '../fixtures/child_table_doctype'; | |||||
import child_table_doctype_1 from '../fixtures/child_table_doctype_1'; | |||||
const doctype_with_child_table_name = doctype_with_child_table.name; | |||||
context('Grid Search', () => { | |||||
before(() => { | |||||
cy.visit('/login'); | |||||
cy.login(); | |||||
cy.visit('/app/website'); | |||||
cy.insert_doc('DocType', child_table_doctype, true); | |||||
cy.insert_doc('DocType', child_table_doctype_1, true); | |||||
cy.insert_doc('DocType', doctype_with_child_table, true); | |||||
return cy.window().its('frappe').then(frappe => { | |||||
return frappe.xcall("frappe.tests.ui_test_helpers.insert_doctype_with_child_table_record", { | |||||
name: doctype_with_child_table_name | |||||
}); | |||||
}); | |||||
}); | |||||
it('Test search row visibility', () => { | |||||
cy.window().its('frappe').then(frappe => { | |||||
frappe.model.user_settings.save('Doctype With Child Table', 'GridView', { | |||||
'Child Table Doctype 1': [ | |||||
{'fieldname': 'data', 'columns': 2}, | |||||
{'fieldname': 'barcode', 'columns': 1}, | |||||
{'fieldname': 'check', 'columns': 1}, | |||||
{'fieldname': 'rating', 'columns': 2}, | |||||
{'fieldname': 'duration', 'columns': 2}, | |||||
{'fieldname': 'date', 'columns': 2} | |||||
] | |||||
}); | |||||
}); | |||||
cy.visit(`/app/doctype-with-child-table/Test Grid Search`); | |||||
cy.get('.frappe-control[data-fieldname="child_table_1"]').as('table'); | |||||
cy.get('@table').find('.grid-row-check:last').click(); | |||||
cy.get('@table').find('.grid-footer').contains('Delete').click(); | |||||
cy.get('.grid-heading-row .grid-row .search').should('not.exist'); | |||||
}); | |||||
it('test search field for different fieldtypes', () => { | |||||
cy.visit(`/app/doctype-with-child-table/Test Grid Search`); | |||||
cy.get('.frappe-control[data-fieldname="child_table_1"]').as('table'); | |||||
// Index Column | |||||
cy.get('@table').find('.grid-heading-row .row-index.search input').type('3'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 2); | |||||
cy.get('@table').find('.grid-heading-row .row-index.search input').clear(); | |||||
// Data Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Data"]').type('Data'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 1); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Data"]').clear(); | |||||
// Barcode Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Barcode"]').type('092'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 4); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Barcode"]').clear(); | |||||
// Check Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Check"]').type('1'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 9); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Check"]').clear(); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Check"]').type('0'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 11); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Check"]').clear(); | |||||
// Rating Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Rating"]').type('3'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 3); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Rating"]').clear(); | |||||
// Duration Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Duration"]').type('3d'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 3); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Duration"]').clear(); | |||||
// Date Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Date"]').type('2022'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 4); | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Date"]').clear(); | |||||
}); | |||||
it('test with multiple filter', () => { | |||||
cy.get('.frappe-control[data-fieldname="child_table_1"]').as('table'); | |||||
// Data Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Data"]').type('a'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 10); | |||||
// Barcode Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Barcode"]').type('0'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 8); | |||||
// Duration Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Duration"]').type('d'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 5); | |||||
// Date Column | |||||
cy.get('@table').find('.grid-heading-row .search input[data-fieldtype="Date"]').type('02-'); | |||||
cy.get('@table').find('.grid-body .rows .grid-row').should('have.length', 2); | |||||
}); | |||||
}); |
@@ -35,7 +35,7 @@ export default class Grid { | |||||
&& this.frm.meta.__form_grid_templates[this.df.fieldname]) { | && this.frm.meta.__form_grid_templates[this.df.fieldname]) { | ||||
this.template = this.frm.meta.__form_grid_templates[this.df.fieldname]; | this.template = this.frm.meta.__form_grid_templates[this.df.fieldname]; | ||||
} | } | ||||
this.filter = {}; | |||||
this.is_grid = true; | this.is_grid = true; | ||||
this.debounced_refresh = this.refresh.bind(this); | this.debounced_refresh = this.refresh.bind(this); | ||||
this.debounced_refresh = frappe.utils.debounce(this.debounced_refresh, 100); | this.debounced_refresh = frappe.utils.debounce(this.debounced_refresh, 100); | ||||
@@ -274,6 +274,8 @@ export default class Grid { | |||||
} | } | ||||
make_head() { | make_head() { | ||||
if (this.prevent_build) return; | |||||
// labels | // labels | ||||
if (this.header_row) { | if (this.header_row) { | ||||
$(this.parent).find(".grid-heading-row .grid-row").remove(); | $(this.parent).find(".grid-heading-row .grid-row").remove(); | ||||
@@ -286,12 +288,42 @@ export default class Grid { | |||||
grid: this, | grid: this, | ||||
configure_columns: true | configure_columns: true | ||||
}); | }); | ||||
this.header_search = new GridRow({ | |||||
parent: $(this.parent).find(".grid-heading-row"), | |||||
parent_df: this.df, | |||||
docfields: this.docfields, | |||||
frm: this.frm, | |||||
grid: this, | |||||
show_search: true | |||||
}); | |||||
Object.keys(this.filter).length !== 0 && | |||||
this.update_search_columns(); | |||||
} | |||||
update_search_columns() { | |||||
for (const field in this.filter) { | |||||
if (this.filter[field] && !this.header_search.search_columns[field]) { | |||||
delete this.filter[field]; | |||||
this.data = this.get_data(Object.keys(this.filter).length !== 0); | |||||
break; | |||||
} | |||||
if (this.filter[field] && this.filter[field].value) { | |||||
let $input = this.header_search.row_index.find('input'); | |||||
if (field && field !== 'row-index') { | |||||
$input = this.header_search.search_columns[field].find('input'); | |||||
} | |||||
$input.val(this.filter[field].value); | |||||
} | |||||
} | |||||
} | } | ||||
refresh(force) { | |||||
refresh() { | |||||
if (this.frm && this.frm.setting_dependency) return; | if (this.frm && this.frm.setting_dependency) return; | ||||
this.data = this.get_data(); | |||||
this.data = this.get_data(Object.keys(this.filter).length !== 0); | |||||
!this.wrapper && this.make(); | !this.wrapper && this.make(); | ||||
let $rows = $(this.parent).find('.rows'); | let $rows = $(this.parent).find('.rows'); | ||||
@@ -453,7 +485,7 @@ export default class Grid { | |||||
} | } | ||||
make_sortable($rows) { | make_sortable($rows) { | ||||
new Sortable($rows.get(0), { | |||||
this.grid_sortable = new Sortable($rows.get(0), { | |||||
group: { name: this.df.fieldname }, | group: { name: this.df.fieldname }, | ||||
handle: '.sortable-handle', | handle: '.sortable-handle', | ||||
draggable: '.grid-row', | draggable: '.grid-row', | ||||
@@ -484,14 +516,78 @@ export default class Grid { | |||||
$(this.frm.wrapper).trigger("grid-make-sortable", [this.frm]); | $(this.frm.wrapper).trigger("grid-make-sortable", [this.frm]); | ||||
} | } | ||||
get_data() { | |||||
var data = this.frm ? | |||||
this.frm.doc[this.df.fieldname] || [] | |||||
: this.df.data || this.get_modal_data(); | |||||
// data.sort(function(a, b) { return a.idx - b.idx}); | |||||
get_data(filter_field) { | |||||
let data = []; | |||||
if (filter_field) { | |||||
data = this.get_filtered_data(); | |||||
} else { | |||||
data = this.frm ? | |||||
this.frm.doc[this.df.fieldname] || [] | |||||
: this.df.data || this.get_modal_data(); | |||||
} | |||||
return data; | return data; | ||||
} | } | ||||
get_filtered_data() { | |||||
if (!this.frm) return; | |||||
let all_data = this.frm.doc[this.df.fieldname]; | |||||
for (const field in this.filter) { | |||||
all_data = all_data.filter(data => { | |||||
let {df, value} = this.filter[field]; | |||||
return this.get_data_based_on_fieldtype(df, data, value.toLowerCase()); | |||||
}); | |||||
} | |||||
return all_data; | |||||
} | |||||
get_data_based_on_fieldtype(df, data, value) { | |||||
let fieldname = df.fieldname; | |||||
let fieldtype = df.fieldtype; | |||||
let fieldvalue = data[fieldname]; | |||||
if (fieldtype === "Check") { | |||||
value = frappe.utils.string_to_boolean(value); | |||||
return (Boolean(fieldvalue) === value) && data; | |||||
} else if (fieldtype === "Sr No" && data.idx.toString().includes(value)) { | |||||
return data; | |||||
} else if (fieldtype === "Duration" && fieldvalue) { | |||||
let formatted_duration = frappe.utils.get_formatted_duration(fieldvalue); | |||||
if (formatted_duration.includes(value)) { | |||||
return data; | |||||
} | |||||
} else if (fieldtype === "Barcode" && fieldvalue) { | |||||
let barcode = fieldvalue.startsWith('<svg') ? | |||||
$(fieldvalue).attr('data-barcode-value') : fieldvalue; | |||||
if (barcode.toLowerCase().includes(value)) { | |||||
return data; | |||||
} | |||||
} else if (["Datetime", "Date"].includes(fieldtype) && fieldvalue) { | |||||
let user_formatted_date = frappe.datetime.str_to_user(fieldvalue); | |||||
if (user_formatted_date.includes(value)) { | |||||
return data; | |||||
} | |||||
} else if (["Currency", "Float", "Int", "Percent", "Rating"].includes(fieldtype)) { | |||||
let num = fieldvalue || 0; | |||||
if (fieldtype === "Rating") { | |||||
let out_of_rating = parseInt(df.options) || 5; | |||||
num = num * out_of_rating; | |||||
} | |||||
if (num.toString().indexOf(value) > -1) { | |||||
return data; | |||||
} | |||||
} else if (fieldvalue && fieldvalue.toLowerCase().includes(value)) { | |||||
return data; | |||||
} | |||||
} | |||||
get_modal_data() { | get_modal_data() { | ||||
return this.df.get_data ? this.df.get_data().filter(data => { | return this.df.get_data ? this.df.get_data().filter(data => { | ||||
if (!this.deleted_docs || !in_list(this.deleted_docs, data.name)) { | if (!this.deleted_docs || !in_list(this.deleted_docs, data.name)) { | ||||
@@ -775,18 +871,19 @@ export default class Grid { | |||||
} | } | ||||
setup_user_defined_columns() { | setup_user_defined_columns() { | ||||
if (this.frm) { | |||||
let user_settings = frappe.get_user_settings(this.frm.doctype, 'GridView'); | |||||
if (user_settings && user_settings[this.doctype] && user_settings[this.doctype].length) { | |||||
this.user_defined_columns = user_settings[this.doctype].map(row => { | |||||
let column = frappe.meta.get_docfield(this.doctype, row.fieldname); | |||||
if (column) { | |||||
column.in_list_view = 1; | |||||
column.columns = row.columns; | |||||
return column; | |||||
} | |||||
}); | |||||
} | |||||
if (!this.frm) return; | |||||
let user_settings = frappe.get_user_settings(this.frm.doctype, 'GridView'); | |||||
if (user_settings && user_settings[this.doctype] && user_settings[this.doctype].length) { | |||||
this.user_defined_columns = user_settings[this.doctype].map(row => { | |||||
let column = frappe.meta.get_docfield(this.doctype, row.fieldname); | |||||
if (column) { | |||||
column.in_list_view = 1; | |||||
column.columns = row.columns; | |||||
return column; | |||||
} | |||||
}); | |||||
} | } | ||||
} | } | ||||
@@ -8,7 +8,7 @@ export default class GridRow { | |||||
this.set_docfields(); | this.set_docfields(); | ||||
this.columns = {}; | this.columns = {}; | ||||
this.columns_list = []; | this.columns_list = []; | ||||
this.row_check_html = '<input type="checkbox" class="grid-row-check pull-left">'; | |||||
this.row_check_html = '<input type="checkbox" class="grid-row-check">'; | |||||
this.make(); | this.make(); | ||||
} | } | ||||
make() { | make() { | ||||
@@ -204,23 +204,65 @@ export default class GridRow { | |||||
})); | })); | ||||
} | } | ||||
render_row(refresh) { | render_row(refresh) { | ||||
var me = this; | |||||
if (this.show_search && !this.show_search_row()) return; | |||||
let me = this; | |||||
this.set_row_index(); | this.set_row_index(); | ||||
// index (1, 2, 3 etc) | // index (1, 2, 3 etc) | ||||
if(!this.row_index) { | |||||
if (!this.row_index && !this.show_search) { | |||||
// REDESIGN-TODO: Make translation contextual, this No is Number | // REDESIGN-TODO: Make translation contextual, this No is Number | ||||
var txt = (this.doc ? this.doc.idx : __("No.")); | var txt = (this.doc ? this.doc.idx : __("No.")); | ||||
this.row_index = $( | |||||
`<div class="row-index sortable-handle col"> | |||||
this.row_check = $( | |||||
`<div class="row-check sortable-handle col"> | |||||
${this.row_check_html} | ${this.row_check_html} | ||||
<span class="hidden-xs">${txt}</span></div>`) | |||||
</div>`) | |||||
.appendTo(this.row); | |||||
this.row_index = $( | |||||
`<div class="row-index sortable-handle col hidden-xs"> | |||||
<span>${txt}</span> | |||||
</div>`) | |||||
.appendTo(this.row) | .appendTo(this.row) | ||||
.on('click', function(e) { | .on('click', function(e) { | ||||
if(!$(e.target).hasClass('grid-row-check')) { | if(!$(e.target).hasClass('grid-row-check')) { | ||||
me.toggle_view(); | me.toggle_view(); | ||||
} | } | ||||
}); | }); | ||||
} else if (this.show_search) { | |||||
this.row_check = $( | |||||
`<div class="row-check col search"></div>` | |||||
).appendTo(this.row); | |||||
this.row_index = $( | |||||
`<div class="row-index col search hidden-xs"> | |||||
<input type="text" class="form-control input-xs text-center" > | |||||
</div>` | |||||
).appendTo(this.row); | |||||
this.row_index.find('input').on('keyup', frappe.utils.debounce((e) => { | |||||
let df = { | |||||
fieldtype: "Sr No" | |||||
}; | |||||
this.grid.filter['row-index'] = { | |||||
df: df, | |||||
value: e.target.value | |||||
}; | |||||
if (e.target.value == "") { | |||||
delete this.grid.filter['row-index']; | |||||
} | |||||
this.grid.grid_sortable | |||||
.option('disabled', Object.keys(this.grid.filter).length !== 0); | |||||
this.grid.prevent_build = true; | |||||
me.grid.refresh(); | |||||
this.grid.prevent_build = false; | |||||
}, 500)); | |||||
frappe.utils.only_allow_num_decimal(this.row_index.find('input')); | |||||
} else { | } else { | ||||
this.row_index.find('span').html(txt); | this.row_index.find('span').html(txt); | ||||
} | } | ||||
@@ -546,6 +588,7 @@ export default class GridRow { | |||||
setup_columns() { | setup_columns() { | ||||
this.focus_set = false; | this.focus_set = false; | ||||
this.search_columns = {}; | |||||
this.grid.setup_visible_columns(); | this.grid.setup_visible_columns(); | ||||
this.grid.visible_columns.forEach((col, ci) => { | this.grid.visible_columns.forEach((col, ci) => { | ||||
@@ -561,8 +604,10 @@ export default class GridRow { | |||||
txt = __(txt); | txt = __(txt); | ||||
} | } | ||||
let column; | let column; | ||||
if (!this.columns[df.fieldname]) { | |||||
if (!this.columns[df.fieldname] && !this.show_search) { | |||||
column = this.make_column(df, colsize, txt, ci); | column = this.make_column(df, colsize, txt, ci); | ||||
} else if (!this.columns[df.fieldname] && this.show_search) { | |||||
column = this.make_search_column(df, colsize); | |||||
} else { | } else { | ||||
column = this.columns[df.fieldname]; | column = this.columns[df.fieldname]; | ||||
this.refresh_field(df.fieldname, txt); | this.refresh_field(df.fieldname, txt); | ||||
@@ -580,6 +625,77 @@ export default class GridRow { | |||||
} | } | ||||
} | } | ||||
}); | }); | ||||
if (this.show_search) { | |||||
// last empty column | |||||
$(`<div class="col grid-static-col col-xs-1"></div>`) | |||||
.appendTo(this.row); | |||||
} | |||||
} | |||||
show_search_row() { | |||||
// show or remove search columns based on grid rows | |||||
this.show_search = this.frm && this.frm.doc && | |||||
this.frm.doc[this.grid.df.fieldname] && | |||||
this.frm.doc[this.grid.df.fieldname].length >= 20; | |||||
!this.show_search && this.wrapper.remove(); | |||||
return this.show_search; | |||||
} | |||||
make_search_column(df, colsize) { | |||||
let title = ""; | |||||
let input_class = ""; | |||||
let is_disabled = ""; | |||||
if (["Text", "Small Text"].includes(df.fieldtype)) { | |||||
input_class = "grid-overflow-no-ellipsis"; | |||||
} else if (["Int", "Currency", "Float", "Percent"].includes(df.fieldtype)) { | |||||
input_class = "text-right"; | |||||
} else if (df.fieldtype === "Check") { | |||||
title = __("1 = True & 0 = False"); | |||||
input_class = "text-center"; | |||||
} else if (df.fieldtype === 'Password') { | |||||
is_disabled = 'disabled'; | |||||
title = __('Password cannot be filtered'); | |||||
} | |||||
let $col = $('<div class="col grid-static-col col-xs-'+colsize+' search"></div>') | |||||
.appendTo(this.row); | |||||
let $search_input = $(` | |||||
<input | |||||
type="text" | |||||
class="form-control input-xs ${input_class}" | |||||
title="${title}" | |||||
data-fieldtype="${df.fieldtype}" | |||||
${is_disabled} | |||||
> | |||||
`).appendTo($col); | |||||
this.search_columns[df.fieldname] = $col; | |||||
$search_input.on('keyup', frappe.utils.debounce((e) => { | |||||
this.grid.filter[df.fieldname] = { | |||||
df: df, | |||||
value: e.target.value | |||||
}; | |||||
if (e.target.value == '') { | |||||
delete this.grid.filter[df.fieldname]; | |||||
} | |||||
this.grid.grid_sortable | |||||
.option('disabled', Object.keys(this.grid.filter).length !== 0); | |||||
this.grid.prevent_build = true; | |||||
this.grid.refresh(); | |||||
this.grid.prevent_build = false; | |||||
}, 500)); | |||||
["Currency", "Float", "Int", "Percent", "Rating"].includes(df.fieldtype) && | |||||
frappe.utils.only_allow_num_decimal($search_input); | |||||
return $col; | |||||
} | } | ||||
make_column(df, colsize, txt, ci) { | make_column(df, colsize, txt, ci) { | ||||
@@ -1102,7 +1102,7 @@ Object.assign(frappe.utils, { | |||||
seconds: round(seconds % 60) | seconds: round(seconds % 60) | ||||
}; | }; | ||||
if (duration_options.hide_days) { | |||||
if (duration_options && duration_options.hide_days) { | |||||
total_duration.hours = round(seconds / 3600); | total_duration.hours = round(seconds / 3600); | ||||
total_duration.days = 0; | total_duration.days = 0; | ||||
} | } | ||||
@@ -1462,5 +1462,23 @@ Object.assign(frappe.utils, { | |||||
console.log(error); // eslint-disable-line | console.log(error); // eslint-disable-line | ||||
return Promise.resolve(name); | return Promise.resolve(name); | ||||
} | } | ||||
}, | |||||
only_allow_num_decimal(input) { | |||||
input.on('input', (e) => { | |||||
let self = $(e.target); | |||||
self.val(self.val().replace(/[^0-9.]/g, '')); | |||||
if ((e.which != 46 || self.val().indexOf('.') != -1) && (e.which < 48 || e.which > 57)) { | |||||
e.preventDefault(); | |||||
} | |||||
}); | |||||
}, | |||||
string_to_boolean(string) { | |||||
switch (string.toLowerCase().trim()) { | |||||
case "t": case "true": case "y": case "yes": case "1": return true; | |||||
case "f": case "false": case "n": case "no": case "0": case null: return false; | |||||
default: return string; | |||||
} | |||||
} | } | ||||
}); | }); |
@@ -89,6 +89,29 @@ | |||||
height: 34px; | height: 34px; | ||||
padding: 8px; | padding: 8px; | ||||
max-height: 200px; | max-height: 200px; | ||||
&.search { | |||||
padding: 7px !important; | |||||
input { | |||||
height: -webkit-fill-available; | |||||
padding: 3px 7px; | |||||
} | |||||
} | |||||
} | |||||
.row-check { | |||||
height: 34px; | |||||
padding: 8px 3px !important; | |||||
text-align: center; | |||||
input { | |||||
margin-right: 0 !important; | |||||
} | |||||
&.search { | |||||
padding: 0 !important; | |||||
} | |||||
} | } | ||||
.grid-row-check { | .grid-row-check { | ||||
@@ -124,7 +147,6 @@ | |||||
.grid-row > .row { | .grid-row > .row { | ||||
.col:last-child { | .col:last-child { | ||||
margin-right: calc(-1 * var(--margin-sm)); | |||||
border-right: none; | border-right: none; | ||||
} | } | ||||
@@ -427,6 +449,7 @@ | |||||
} | } | ||||
.page-number { | .page-number { | ||||
background-color: var(--fg-color); | |||||
padding: 0 3px; | padding: 0 3px; | ||||
} | } | ||||
@@ -272,4 +272,47 @@ def update_child_table(name): | |||||
'options': 'Doctype to Link' | 'options': 'Doctype to Link' | ||||
}) | }) | ||||
doc.save() | |||||
doc.save() | |||||
@frappe.whitelist() | |||||
def insert_doctype_with_child_table_record(name): | |||||
if frappe.db.get_all(name, {'title': 'Test Grid Search'}): | |||||
return | |||||
def insert_child(doc, data, barcode, check, rating, duration, date): | |||||
doc.append('child_table_1', { | |||||
'data': data, | |||||
'barcode': barcode, | |||||
'check': check, | |||||
'rating': rating, | |||||
'duration': duration, | |||||
'date': date, | |||||
}) | |||||
doc = frappe.new_doc(name) | |||||
doc.title = 'Test Grid Search' | |||||
doc.append('child_table', {'title': 'Test Grid Search'}) | |||||
insert_child(doc, 'Data', '09709KJKKH2432', 1, 0.5, 266851, "2022-02-21") | |||||
insert_child(doc, 'Test', '09209KJHKH2432', 1, 0.8, 547877, "2021-05-27") | |||||
insert_child(doc, 'New', '09709KJHYH1132', 0, 0.1, 3, "2019-03-02") | |||||
insert_child(doc, 'Old', '09701KJHKH8750', 0, 0, 127455, "2022-01-11") | |||||
insert_child(doc, 'Alpha', '09204KJHKH2432', 0, 0.6, 364, "2019-12-31") | |||||
insert_child(doc, 'Delta', '09709KSPIO2432', 1, 0.9, 1242000, "2020-04-21") | |||||
insert_child(doc, 'Update', '76989KJLVA2432', 0, 1, 183845, "2022-02-10") | |||||
insert_child(doc, 'Delete', '29189KLHVA1432', 0, 0, 365647, "2021-05-07") | |||||
insert_child(doc, 'Make', '09689KJHAA2431', 0, 0.3, 24, "2020-11-11") | |||||
insert_child(doc, 'Create', '09709KLKKH2432', 1, 0.3, 264851, "2021-02-21") | |||||
insert_child(doc, 'Group', '09209KJLKH2432', 1, 0.8, 537877, "2020-03-15") | |||||
insert_child(doc, 'Slide', '01909KJHYH1132', 0, 0.5, 9, "2018-03-02") | |||||
insert_child(doc, 'Drop', '09701KJHKH8750', 1, 0, 127255, "2018-01-01") | |||||
insert_child(doc, 'Beta', '09204QJHKN2432', 0, 0.6, 354, "2017-12-30") | |||||
insert_child(doc, 'Flag', '09709KXPIP2432', 1, 0, 1241000, "2021-04-21") | |||||
insert_child(doc, 'Upgrade', '75989ZJLVA2432', 0.8, 1, 183645, "2020-08-13") | |||||
insert_child(doc, 'Down', '28189KLHRA1432', 1, 0, 362647, "2020-06-17") | |||||
insert_child(doc, 'Note', '09689DJHAA2431', 0, 0.1, 29, "2021-09-11") | |||||
insert_child(doc, 'Click', '08189DJHAA2431', 1, 0.3, 209, "2020-07-04") | |||||
insert_child(doc, 'Drag', '08189DIHAA2981', 0, 0.7, 342628, "2022-05-04") | |||||
doc.insert() |