[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:
@@ -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;
|
||||
|
||||
@@ -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 ||
|
||||
(() => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user