[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) <lpe@odoo.com>
This commit is contained in:
Mathieu Duckerts-Antoine
2022-08-29 13:49:09 +02:00
co-authored by Lucas Perais
parent 481acba93b
commit 9b1456a2ec
4 changed files with 39 additions and 27 deletions
@@ -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;
}
@@ -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";
@@ -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;
@@ -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 })"
>
<t t-esc="create.string"/>
</a>