[REF] web: model is no longer an event bus

In order to make the model reactive, it must not be an EventBus. An EventBus cannot be reactive. So we will add a key bus to the model that will always trigger all events that were triggered on the model before.

Part of task 3179751

closes odoo/odoo#114975

Related: odoo/enterprise#38032
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
FrancoisGe
2023-03-10 18:55:03 +01:00
parent da9febc5c8
commit 88b148b66b
16 changed files with 41 additions and 47 deletions
@@ -8,7 +8,7 @@ export class InventoryReportListController extends ListController {
setup() {
super.setup();
if (this.props.context.inventory_mode || this.props.context.inventory_report_mode) {
useBus(this.model, "record-updated", this.recordUpdated);
useBus(this.model.bus, "record-updated", this.recordUpdated);
}
}
@@ -180,7 +180,7 @@ export class Record extends DataPoint {
async askChanges() {
const proms = [];
this.model.trigger("NEED_LOCAL_CHANGES", { proms });
this.model.bus.trigger("NEED_LOCAL_CHANGES", { proms });
return Promise.all([...proms, this._updatePromise]);
}
@@ -674,7 +674,7 @@ export class Record extends DataPoint {
async urgentSave() {
this.model.__bm__.bypassMutex = true;
this._urgentSave = true;
this.model.trigger("WILL_SAVE_URGENTLY");
this.model.bus.trigger("WILL_SAVE_URGENTLY");
await Promise.resolve();
this.__syncData();
let isValid = true;
@@ -48,8 +48,8 @@ export class AceField extends Component {
);
const { model } = this.props.record;
useBus(model, "WILL_SAVE_URGENTLY", () => this.commitChanges());
useBus(model, "NEED_LOCAL_CHANGES", ({ detail }) =>
useBus(model.bus, "WILL_SAVE_URGENTLY", () => this.commitChanges());
useBus(model.bus, "NEED_LOCAL_CHANGES", ({ detail }) =>
detail.proms.push(this.commitChanges())
);
}
@@ -55,13 +55,13 @@ export class DateField extends Component {
}
}
onDatePickerInput(ev) {
this.props.record.model.trigger(
this.props.record.model.bus.trigger(
"FIELD_IS_DIRTY",
ev.target.value !== this.lastSetValue
);
}
onUpdateInput(date) {
this.props.record.model.trigger("FIELD_IS_DIRTY", false);
this.props.record.model.bus.trigger("FIELD_IS_DIRTY", false);
this.lastSetValue = date;
}
}
@@ -40,13 +40,13 @@ export class DateTimeField extends Component {
}
}
onDatePickerInput(ev) {
this.props.record.model.trigger(
this.props.record.model.bus.trigger(
"FIELD_IS_DIRTY",
ev.target.value !== this.lastSetValue
);
}
onUpdateInput(date) {
this.props.record.model.trigger("FIELD_IS_DIRTY", false);
this.props.record.model.bus.trigger("FIELD_IS_DIRTY", false);
this.lastSetValue = date;
}
}
@@ -48,7 +48,7 @@ export class DomainField extends Component {
}
});
useBus(this.props.record.model, "NEED_LOCAL_CHANGES", async (ev) => {
useBus(this.props.record.model.bus, "NEED_LOCAL_CHANGES", async (ev) => {
if (this.isDebugEdited) {
const prom = this.loadCount(this.props);
ev.detail.proms.push(prom);
@@ -45,7 +45,7 @@ export function useInputField(params) {
*/
function onInput(ev) {
isDirty = ev.target.value !== lastSetValue;
component.props.record.model.trigger("FIELD_IS_DIRTY", isDirty);
component.props.record.model.bus.trigger("FIELD_IS_DIRTY", isDirty);
}
/**
@@ -76,7 +76,7 @@ export function useInputField(params) {
lastSetValue = ev.target.value;
}
component.props.record.model.trigger("FIELD_IS_DIRTY", isDirty);
component.props.record.model.bus.trigger("FIELD_IS_DIRTY", isDirty);
}
}
function onKeydown(ev) {
@@ -116,10 +116,8 @@ export function useInputField(params) {
});
const { model } = component.props.record;
useBus(model, "WILL_SAVE_URGENTLY", () => commitChanges(true));
useBus(model, "NEED_LOCAL_CHANGES", (ev) =>
ev.detail.proms.push(commitChanges())
);
useBus(model.bus, "WILL_SAVE_URGENTLY", () => commitChanges(true));
useBus(model.bus, "NEED_LOCAL_CHANGES", (ev) => ev.detail.proms.push(commitChanges()));
/**
* Roughly the same as onChange, but called at more specific / critical times. (See bus events)
@@ -154,7 +152,7 @@ export function useInputField(params) {
if ((val || false) !== (component.props.record.data[component.props.name] || false)) {
await component.props.record.update({ [component.props.name]: val });
lastSetValue = inputRef.el.value;
component.props.record.model.trigger("FIELD_IS_DIRTY", isDirty);
component.props.record.model.bus.trigger("FIELD_IS_DIRTY", isDirty);
}
}
}
@@ -478,7 +478,7 @@ export class X2ManyFieldDialog extends Component {
this.title = this.props.title;
useSubEnv({ config: this.props.config });
useBus(this.record.model, "update", () => this.render(true));
useBus(this.record.model.bus, "update", () => this.render(true));
this.modalRef = useChildRef();
@@ -250,7 +250,7 @@ export class X2ManyField extends Component {
if (editable) {
if (this.list.editedRecord) {
const proms = [];
this.list.model.trigger("NEED_LOCAL_CHANGES", { proms });
this.list.model.bus.trigger("NEED_LOCAL_CHANGES", { proms });
await Promise.all([...proms, this.list.editedRecord._updatePromise]);
await this.list.editedRecord.switchMode("readonly", { checkValidity: true });
}
@@ -9,7 +9,7 @@ export class FormStatusIndicator extends Component {
fieldIsDirty: false,
});
useBus(
this.props.model,
this.props.model.bus,
"FIELD_IS_DIRTY",
(ev) => (this.state.fieldIsDirty = ev.detail)
);
@@ -85,12 +85,12 @@ class KanbanGroup extends Group {
},
});
this.model.addEventListener("record-updated", ({ detail }) => {
this.model.bus.addEventListener("record-updated", ({ detail }) => {
const { record, relatedRecords } = detail;
const localIds = this.records.map((r) => r.id);
const updatedIds = [record, ...relatedRecords].map((r) => r.id);
if (localIds.some((id) => updatedIds.includes(id))) {
this.model.trigger("group-updated", {
this.model.bus.trigger("group-updated", {
group: this,
withProgressBars: true,
});
@@ -114,7 +114,7 @@ class KanbanGroup extends Group {
*/
async deleteRecords() {
const records = await super.deleteRecords(...arguments);
this.model.trigger("group-updated", {
this.model.bus.trigger("group-updated", {
group: this,
withProgressBars: true,
});
@@ -207,7 +207,7 @@ class KanbanGroup extends Group {
// Do not update progress bars data when filtering on them.
await Promise.all([this.list.load()]);
this.model.trigger("group-updated", { group: this, withProgressBars: false });
this.model.bus.trigger("group-updated", { group: this, withProgressBars: false });
}
/**
@@ -306,7 +306,7 @@ class KanbanGroup extends Group {
await this.model.reloadRecords(record);
record.switchMode("readonly");
this.addRecord(record, 0);
this.model.trigger("group-updated", {
this.model.bus.trigger("group-updated", {
group: this,
withProgressBars: true,
});
@@ -353,7 +353,7 @@ export class KanbanDynamicGroupList extends DynamicGroupList {
this.groupBy = this.groupBy.slice(0, 1);
this.model.addEventListener("group-updated", async ({ detail }) => {
this.model.bus.addEventListener("group-updated", async ({ detail }) => {
if (this.groups.some((g) => g.id === detail.group.id)) {
await this.updateGroupProgressData([detail.group], detail.withProgressBars);
this.model.notify();
@@ -154,23 +154,19 @@ export class ListRenderer extends Component {
// not very beautiful but works: refactor at some point
this.lastCellFocused;
useBus(this.props.list.model, "list-confirmation-dialog-will-open", () => {
useBus(this.props.list.model.bus, "list-confirmation-dialog-will-open", () => {
if (this.tableRef.el.contains(document.activeElement)) {
this.lastCellFocused = document.activeElement.closest("td");
}
});
useBus(this.props.list.model, "list-confirmation-dialog-closed", () => {
useBus(this.props.list.model.bus, "list-confirmation-dialog-closed", () => {
if (this.lastCellFocused) {
this.focus(this.lastCellFocused);
}
});
useBus(
this.props.list.model,
"FIELD_IS_DIRTY",
(ev) => (this.lastIsDirty = ev.detail)
);
useBus(this.props.list.model.bus, "FIELD_IS_DIRTY", (ev) => (this.lastIsDirty = ev.detail));
useBounceButton(this.rootRef, () => {
return this.showNoContentHelper;
+4 -4
View File
@@ -11,15 +11,15 @@ import { EventBus, onWillStart, onWillUpdateProps, useComponent } from "@odoo/ow
* @typedef {import("@web/search/search_model").SearchParams} SearchParams
*/
export class Model extends EventBus {
export class Model {
/**
* @param {Object} env
* @param {Object} services
*/
constructor(env, params, services) {
super();
this.env = env;
this.orm = services.orm;
this.bus = new EventBus();
this.useSampleModel = false; // will be set to true by the "useModel" hook if necessary
this.setup(params, services);
}
@@ -59,7 +59,7 @@ export class Model extends EventBus {
}
notify() {
this.trigger("update");
this.bus.trigger("update");
}
}
Model.services = [];
@@ -98,7 +98,7 @@ export function useModel(ModelClass, params, options = {}) {
const model = new ModelClass(component.env, params, services);
useBus(
model,
model.bus,
"update",
options.onUpdate ||
(() => {
+1 -1
View File
@@ -26,7 +26,7 @@ class _Record extends Component {
}
this.model = new RelationalModel(this.env, modelParams, modelServices);
useBus(this.model, "update", () => this.render(true));
useBus(this.model.bus, "update", () => this.render(true));
let loadKey;
const load = (props) => {
@@ -558,7 +558,7 @@ export class Record extends DataPoint {
*/
async urgentSave() {
this._urgentSave = true;
this.model.trigger("WILL_SAVE_URGENTLY");
this.model.bus.trigger("WILL_SAVE_URGENTLY");
return this._save({ stayInEdition: true, noReload: true });
}
@@ -571,7 +571,7 @@ export class Record extends DataPoint {
async askChanges() {
const proms = [];
this.model.trigger("NEED_LOCAL_CHANGES", { proms });
this.model.bus.trigger("NEED_LOCAL_CHANGES", { proms });
await Promise.all([...proms, this.model.mutex.getUnlockedDef()]);
}
@@ -1792,11 +1792,11 @@ class DynamicList extends DataPoint {
record,
fieldNodes: this.model.fieldNodes,
};
this.model.trigger("list-confirmation-dialog-will-open");
this.model.bus.trigger("list-confirmation-dialog-will-open");
await new Promise((resolve) => {
this.model.dialogService.add(ListConfirmationDialog, dialogProps, {
onClose: () => {
this.model.trigger("list-confirmation-dialog-closed");
this.model.bus.trigger("list-confirmation-dialog-closed");
resolve();
},
});
@@ -3677,7 +3677,7 @@ export class RelationalModel extends Model {
await Promise.all([record, ...relatedRecords].map((r) => r.load()));
this.trigger("record-updated", { record, relatedRecords });
this.bus.trigger("record-updated", { record, relatedRecords });
this.notify();
}
}
@@ -92,10 +92,10 @@ export class HtmlField extends Component {
});
const { model } = this.props.record;
useBus(model, "WILL_SAVE_URGENTLY", () =>
useBus(model.bus, "WILL_SAVE_URGENTLY", () =>
this.commitChanges({ urgent: true })
);
useBus(model, "NEED_LOCAL_CHANGES", ({ detail }) =>
useBus(model.bus, "NEED_LOCAL_CHANGES", ({ detail }) =>
detail.proms.push(this.commitChanges())
);
@@ -298,7 +298,7 @@ export class HtmlField extends Component {
!(!lastValue && stripHistoryIds(value) === "<p><br></p>") &&
stripHistoryIds(value) !== stripHistoryIds(lastValue)
) {
this.props.record.model.trigger("FIELD_IS_DIRTY", false);
this.props.record.model.bus.trigger("FIELD_IS_DIRTY", false);
this.currentEditingValue = value;
await this.props.record.update({ [this.props.name]: value });
}
@@ -319,7 +319,7 @@ export class HtmlField extends Component {
$codeviewButtonToolbar.click(this.toggleCodeView.bind(this));
}
this.wysiwyg.odooEditor.editable.addEventListener("input", () =>
this.props.record.model.trigger("FIELD_IS_DIRTY", this._isDirty())
this.props.record.model.bus.trigger("FIELD_IS_DIRTY", this._isDirty())
);
this.isRendered = true;