ソースを参照

Merge pull request #16070 from shariquerik/grid-search-feat

feat: Grid Search
version-14
mergify[bot] 3年前
committed by GitHub
コミット
b176443792
この署名に対応する既知のキーがデータベースに存在しません GPGキーID: 4AEE18F83AFDEB23
9個のファイルの変更502行の追加31行の削除
  1. +59
    -0
      cypress/fixtures/child_table_doctype_1.js
  2. +6
    -0
      cypress/fixtures/doctype_with_child_table.js
  3. +2
    -0
      cypress/integration/dashboard_links.js
  4. +107
    -0
      cypress/integration/grid_search.js
  5. +118
    -21
      frappe/public/js/frappe/form/grid.js
  6. +123
    -7
      frappe/public/js/frappe/form/grid_row.js
  7. +19
    -1
      frappe/public/js/frappe/utils/utils.js
  8. +24
    -1
      frappe/public/scss/common/grid.scss
  9. +44
    -1
      frappe/tests/ui_test_helpers.py

+ 59
- 0
cypress/fixtures/child_table_doctype_1.js ファイルの表示

@@ -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
};

+ 6
- 0
cypress/fixtures/doctype_with_child_table.js ファイルの表示

@@ -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: [],


+ 2
- 0
cypress/integration/dashboard_links.js ファイルの表示

@@ -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 => {


+ 107
- 0
cypress/integration/grid_search.js ファイルの表示

@@ -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);
});
});

+ 118
- 21
frappe/public/js/frappe/form/grid.js ファイルの表示

@@ -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;
}
});
} }
} }




+ 123
- 7
frappe/public/js/frappe/form/grid_row.js ファイルの表示

@@ -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) {


+ 19
- 1
frappe/public/js/frappe/utils/utils.js ファイルの表示

@@ -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;
}
} }
}); });

+ 24
- 1
frappe/public/scss/common/grid.scss ファイルの表示

@@ -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;
} }




+ 44
- 1
frappe/tests/ui_test_helpers.py ファイルの表示

@@ -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()

読み込み中…
キャンセル
保存