[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:
co-authored by
Lucas Perais
parent
481acba93b
commit
9b1456a2ec
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user