From 9b1456a2ec9bab9e705029eb4ee2c18ceca73fcb Mon Sep 17 00:00:00 2001 From: Mathieu Duckerts-Antoine Date: Mon, 22 Aug 2022 14:18:35 +0000 Subject: [PATCH] [REF] web: x2manyField: edit/add records inline conditionally The aim of this commit is to provide better API points to be able to extend the behavior of the X2ManyField in conjunction with the ListRenderer. More precisely, we make possible to specify record by record if it should be edited/created inline or in a dialog. Part-of: odoo/odoo#97984 Co-authored-by: Lucas Perais (lpe) --- .../src/views/fields/relational_utils.js | 6 ++-- .../src/views/fields/x2many/x2many_field.js | 30 ++++++++++--------- .../static/src/views/list/list_renderer.js | 28 +++++++++++------ .../static/src/views/list/list_renderer.xml | 2 +- 4 files changed, 39 insertions(+), 27 deletions(-) diff --git a/addons/web/static/src/views/fields/relational_utils.js b/addons/web/static/src/views/fields/relational_utils.js index 26d1ace3f1e..a175ea72f5b 100644 --- a/addons/web/static/src/views/fields/relational_utils.js +++ b/addons/web/static/src/views/fields/relational_utils.js @@ -545,14 +545,14 @@ async function getFormViewInfo({ list, activeField, viewService, userService, en return formViewInfo; } -export function useAddInlineRecord({ position, addNew }) { +export function useAddInlineRecord({ addNew }) { let creatingRecord = false; - async function addInlineRecord({ context }) { + async function addInlineRecord({ context, editable }) { if (!creatingRecord) { creatingRecord = true; try { - await addNew({ context, mode: "edit", position }); + await addNew({ context, mode: "edit", position: editable }); } finally { creatingRecord = false; } diff --git a/addons/web/static/src/views/fields/x2many/x2many_field.js b/addons/web/static/src/views/fields/x2many/x2many_field.js index 245f2ef7a7c..e2998a018b7 100644 --- a/addons/web/static/src/views/fields/x2many/x2many_field.js +++ b/addons/web/static/src/views/fields/x2many/x2many_field.js @@ -34,8 +34,8 @@ export class X2ManyField extends Component { this.isMany2Many ); - const subView = this.activeField.views[this.viewMode]; - const subViewActiveActions = subView.activeActions; + const archInfo = this.activeField.views[this.viewMode]; + const subViewActiveActions = archInfo.activeActions; this.activeActions = useActiveActions({ crudOptions: Object.assign({}, this.activeField.options, { onDelete: removeRecord, @@ -50,12 +50,9 @@ export class X2ManyField extends Component { }, }); - if (subView.editable) { - this.addInLine = useAddInlineRecord({ - position: subView.editable, - addNew: (...args) => this.list.addNew(...args), - }); - } + this.addInLine = useAddInlineRecord({ + addNew: (...args) => this.list.addNew(...args), + }); const openRecord = useOpenX2ManyRecord({ resModel: this.list.resModel, @@ -194,13 +191,17 @@ export class X2ManyField extends Component { } }); + const editable = archInfo.editable || this.props.editable; props.activeActions = this.activeActions; props.archInfo = { ...archInfo, columns }; props.cycleOnTab = false; - props.editable = !this.props.readonly && archInfo.editable; + props.editable = !this.props.readonly && editable; props.nestedKeyOptionalFieldsData = this.nestedKeyOptionalFieldsData; - props.onAdd = this.onAdd.bind(this); - + props.onAdd = (params) => { + params.editable = + !this.props.readonly && ("editable" in params ? params.editable : editable); + this.onAdd(params); + }; return props; } @@ -211,7 +212,7 @@ export class X2ManyField extends Component { return false; } - async onAdd({ context } = {}) { + async onAdd({ context, editable } = {}) { const record = this.props.record; const domain = record.getFieldDomain(this.props.name).toList(); if (context) { @@ -220,7 +221,7 @@ export class X2ManyField extends Component { if (this.isMany2Many) { return this.selectCreate({ domain, context }); } - if (this.addInLine) { + if (editable) { if (this.list.editedRecord) { const proms = []; this.list.model.env.bus.trigger("RELATIONAL_MODEL:NEED_LOCAL_CHANGES", { proms }); @@ -228,7 +229,7 @@ export class X2ManyField extends Component { await this.list.editedRecord.switchMode("readonly"); } if (!this.list.editedRecord) { - return this.addInLine({ context }); + return this.addInLine({ context, editable }); } return; } @@ -243,6 +244,7 @@ X2ManyField.components = { Pager, KanbanRenderer, ListRenderer }; X2ManyField.props = { ...standardFieldProps, addLabel: { type: "string", optional: true }, + editable: { type: "string", optional: true }, }; X2ManyField.supportedTypes = ["one2many"]; X2ManyField.template = "web.X2ManyField"; diff --git a/addons/web/static/src/views/list/list_renderer.js b/addons/web/static/src/views/list/list_renderer.js index b0addd99383..c225700edcf 100644 --- a/addons/web/static/src/views/list/list_renderer.js +++ b/addons/web/static/src/views/list/list_renderer.js @@ -192,6 +192,10 @@ export class ListRenderer extends Component { return this.props.hasSelectors && !this.env.isSmall; } + add(params) { + this.props.onAdd(params); + } + // The following code manipulates the DOM directly to avoid having to wait for a // render + patch which would occur on the next frame and cause flickering. freezeColumnWidths() { @@ -831,7 +835,7 @@ export class ListRenderer extends Component { await recordAfterResequence(); await record.switchMode("edit"); this.cellToFocus = { column, record }; - } else if (this.props.editable) { + } else if (this.isInlineEditable(record)) { if (record.isInEdition) { this.focusCell(column); this.cellToFocus = null; @@ -927,6 +931,12 @@ export class ListRenderer extends Component { return futureCell && getElementToFocus(futureCell); } + isInlineEditable(record) { + // /!\ the keyboard navigation works under the hypothesis that all or + // none records are editable. + return !!this.props.editable; + } + /** * @param {KeyboardEvent} ev * @param { import('@web/views/relational_model').Group @@ -1076,7 +1086,7 @@ export class ListRenderer extends Component { record.checkValidity() && (isEnterBehavior || isTabBehavior) ) { - this.props.onAdd({ group }); + this.add({ group }); return true; } return false; @@ -1116,14 +1126,14 @@ export class ListRenderer extends Component { // add a line if (record.checkValidity()) { const { context } = this.creates[0]; - this.props.onAdd({ context }); + this.add({ context }); } } else if ( activeActions.create && !record.canBeAbandoned && (record.isDirty || this.lastIsDirty) ) { - this.props.onAdd({ group }); + this.add({ group }); } else if (cycleOnTab) { if (record.canBeAbandoned) { list.unselectRecord(true); @@ -1187,14 +1197,14 @@ export class ListRenderer extends Component { // add a line if (record.checkValidity()) { const { context } = this.creates[0]; - this.props.onAdd({ context }); + this.add({ context }); } } else if ( activeActions.create && !record.canBeAbandoned && (record.isDirty || this.lastIsDirty) ) { - this.props.onAdd({ group }); + this.add({ group }); } else if (cycleOnTab) { if (record.canBeAbandoned) { list.unselectRecord(true); @@ -1258,7 +1268,7 @@ export class ListRenderer extends Component { if (futureRecord) { futureRecord.switchMode("edit"); } else if (this.lastIsDirty || !record.canBeAbandoned || this.displayRowCreates) { - this.props.onAdd({ group }); + this.add({ group }); } else { futureRecord = list.records.at(0); futureRecord.switchMode("edit"); @@ -1395,7 +1405,7 @@ export class ListRenderer extends Component { return true; } - if (this.props.editable || applyMultiEditBehavior) { + if (this.isInlineEditable(record) || applyMultiEditBehavior) { const column = this.state.columns.find( (c) => c.name === cell.getAttribute("name") ); @@ -1427,7 +1437,7 @@ export class ListRenderer extends Component { if (this.createProm) { return; } - this.props.onAdd({ context }); + this.add({ context }); this.createProm = Promise.resolve(); this.createProm.then(() => { this.lastCreatingAction = true; diff --git a/addons/web/static/src/views/list/list_renderer.xml b/addons/web/static/src/views/list/list_renderer.xml index 465f9a90630..737f8982dd2 100644 --- a/addons/web/static/src/views/list/list_renderer.xml +++ b/addons/web/static/src/views/list/list_renderer.xml @@ -86,7 +86,7 @@ role="button" t-att-class="create_index !== 0 ? 'ml16' : ''" t-att-tabindex="props.list.editedRecord ? '-1' : '0'" - t-on-click.stop.prevent="() => this.props.onAdd({context: create.context})" + t-on-click.stop.prevent="() => this.add({ context: create.context })" >