[IMP] mail: move boot code in service

Part of task-2582313

closes odoo/odoo#75147

Signed-off-by: Alexandre Kühn (aku) <aku@odoo.com>
This commit is contained in:
Sébastien Theys
2021-08-18 12:26:41 +00:00
parent 5377376097
commit ffd3e48e90
7 changed files with 134 additions and 107 deletions
-5
View File
@@ -9,10 +9,6 @@ import { nextTick } from '@mail/utils/utils';
*/
export function addMessagingToEnv(providedEnv = {}) {
const env = { ...providedEnv };
/**
* Registry of models.
*/
env.models = {};
/**
* Environment keys used in messaging.
*/
@@ -34,7 +30,6 @@ export function addMessagingToEnv(providedEnv = {}) {
return this.messaging.isInitialized;
},
messagingCreatedPromise: makeDeferred(),
messagingInitializedDeferred: makeDeferred(),
});
return env;
}
+5 -34
View File
@@ -1,45 +1,17 @@
/** @odoo-module **/
import { ModelManager } from '@mail/model/model_manager';
import MessagingService from '@mail/services/messaging/messaging';
import { makeDeferred } from '@mail/utils/deferred/deferred';
import env from 'web.commonEnv';
import { serviceRegistry } from 'web.core';
async function createMessaging() {
await new Promise(resolve => {
/**
* Called when all JS resources are loaded. This is useful in order
* to do some processing after other JS files have been parsed, for
* example new models or patched models that are coming from
* other modules, because some of those patches might need to be
* applied before messaging initialization.
*/
window.addEventListener('load', resolve);
});
/**
* All JS resources are loaded, but not necessarily processed.
* We assume no messaging-related modules return any Promise,
* therefore they should be processed *at most* asynchronously at
* "Promise time".
*/
await new Promise(resolve => setTimeout(resolve));
/**
* Some models require session data, like locale text direction (depends on
* fully loaded translation).
*/
await env.session.is_bound;
env.modelManager.start();
}
/**
* Environment keys used in messaging.
*/
Object.assign(env, {
isMessagingInitialized() {
if (!this.modelManager.messaging) {
if (!this.modelManager || !this.modelManager.messaging) {
return false;
}
return this.modelManager.messaging.isInitialized;
@@ -50,17 +22,16 @@ Object.assign(env, {
* Useful for discuss widget to know when messaging is created, because this
* is an essential condition to make it work.
*/
messagingCreatedPromise: createMessaging(),
modelManager: new ModelManager(env),
messagingCreatedPromise: makeDeferred(),
});
Object.defineProperty(env, 'messaging', {
get() {
return this.modelManager.messaging;
return this.modelManager && this.modelManager.messaging;
},
});
Object.defineProperty(env, 'models', {
get() {
return this.modelManager.models;
return this.modelManager && this.modelManager.models;
},
});
@@ -6,6 +6,7 @@ import AbstractService from 'web.AbstractService';
import { bus, serviceRegistry } from 'web.core';
const ChatWindowService = AbstractService.extend({
dependencies: ['messaging'],
/**
* @override {web.AbstractService}
*/
@@ -6,6 +6,7 @@ import AbstractService from 'web.AbstractService';
import { bus, serviceRegistry } from 'web.core';
const DialogService = AbstractService.extend({
dependencies: ['messaging'],
/**
* @override {web.AbstractService}
*/
@@ -1,14 +1,56 @@
/** @odoo-module **/
import { ModelManager } from '@mail/model/model_manager';
import AbstractService from 'web.AbstractService';
export default AbstractService.extend({
dependencies: ['bus_service'],
/**
* @override {web.AbstractService}
* @override
*/
start() {
init() {
this._super(...arguments);
this.env.messagingCreatedPromise.then(() => this.env.messaging.start());
this._modelManager = new ModelManager(this.env);
this.env.modelManager = this._modelManager;
},
/**
* @override
*/
async start() {
this._super(...arguments);
if (document.readyState === 'loading') {
await new Promise(resolve => {
/**
* Called when all JS resources are loaded. This is useful in order
* to do some processing after other JS files have been parsed, for
* example new models or patched models that are coming from
* other modules, because some of those patches might need to be
* applied before messaging initialization.
*/
window.addEventListener('load', resolve);
});
}
/**
* All JS resources are loaded, but not necessarily processed.
* We assume no messaging-related modules return any Promise,
* therefore they should be processed *at most* asynchronously at
* "Promise time".
*/
await new Promise(resolve => setTimeout(resolve));
/**
* Some models require session data, like locale text direction (depends on
* fully loaded translation).
*/
await this.env.session.is_bound;
await this.startModelManager();
this.env.messagingCreatedPromise.resolve();
await this.env.messaging.start();
},
/**
* Starts the model manager.
*/
async startModelManager() {
await this._modelManager.start();
},
});
+74 -52
View File
@@ -6,8 +6,9 @@ import {
addMessagingToEnv,
addTimeControlToEnv,
} from '@mail/env/test_env';
import { ModelManager } from '@mail/model/model_manager';
import ChatWindowService from '@mail/services/chat_window_service/chat_window_service';
import MessagingService from '@mail/services/messaging/messaging';
import { makeDeferred } from '@mail/utils/deferred/deferred';
import DialogService from '@mail/services/dialog_service/dialog_service';
import { getMessagingComponent } from '@mail/utils/messaging_component';
import { nextTick } from '@mail/utils/utils';
@@ -483,7 +484,7 @@ async function start(param0 = {}) {
} = callbacks;
const { debug = false } = param0;
initCallbacks.forEach(callback => callback(param0));
const testSetupDoneDeferred = makeDeferred();
let env = Object.assign(providedEnv || {});
env.session = Object.assign(
{
@@ -520,6 +521,56 @@ async function start(param0 = {}) {
_listenHomeMenu: () => {},
}),
local_storage: AbstractStorageService.extend({ storage: new RamStorage() }),
messaging: MessagingService.extend({
/**
* Override to bind the getters on the actual env that is given,
* because the env in the scope of this test might only serve as
* template and not be the one actually used.
*
* @override
*/
init() {
this._super(...arguments);
Object.defineProperty(this.env, 'messaging', {
get() {
return this.modelManager.messaging;
},
});
Object.defineProperty(this.env, 'models', {
get() {
return this.modelManager.models;
},
});
},
/**
* Override to control when messaging is created, useful to test
* spinners and race conditions.
*
* @override
*/
async start() {
const _super = this._super.bind(this);
await messagingBeforeCreationDeferred;
await _super();
},
/**
* Override to ensure the test setup is complete before starting
* otherwise for example the mock server might not be ready yet.
* And also override to give test values to messaging.
*
* @override
*/
async startModelManager() {
await testSetupDoneDeferred;
await this._modelManager.start({
autofetchPartnerImStatus: false,
disableAnimation: true,
isQUnitTest: true,
loadingBaseDelayDuration,
messagingBus,
});
},
}),
}, param0.services);
const kwargs = Object.assign({}, param0, {
@@ -615,18 +666,6 @@ async function start(param0 = {}) {
}
// get the final test env after execution of createView/createWebClient/addMockEnvironment
testEnv = Component.env;
const modelManager = new ModelManager(testEnv);
Object.assign(testEnv, { modelManager });
Object.defineProperty(testEnv, 'messaging', {
get() {
return this.modelManager.messaging;
},
});
Object.defineProperty(testEnv, 'models', {
get() {
return this.modelManager.models;
},
});
/**
* Returns a promise resolved after the expected event is received.
*
@@ -671,51 +710,34 @@ async function start(param0 = {}) {
await funcRes;
});
let waitUntilEventPromise;
if (waitUntilEvent) {
waitUntilEventPromise = afterEvent({ func: () => testSetupDoneDeferred.resolve(), ...waitUntilEvent, });
} else {
testSetupDoneDeferred.resolve();
waitUntilEventPromise = Promise.resolve();
}
const result = {
afterEvent,
env: testEnv,
mockServer,
widget,
};
const start = async () => {
messagingBeforeCreationDeferred.then(async () => {
/**
* Some models require session data, like locale text direction
* (depends on fully loaded translation).
*/
await env.session.is_bound;
testEnv.modelManager.start({
autofetchPartnerImStatus: false,
disableAnimation: true,
isQUnitTest: true,
loadingBaseDelayDuration,
messagingBus,
});
modelManager.messaging.start().then(() =>
testEnv.messagingInitializedDeferred.resolve()
);
testEnv.messagingCreatedPromise.resolve();
});
if (waitUntilMessagingCondition === 'created') {
await testEnv.messagingCreatedPromise;
}
if (waitUntilMessagingCondition === 'initialized') {
await testEnv.messagingInitializedDeferred;
}
if (mountCallbacks.length > 0) {
await afterNextRender(async () => {
await Promise.all(mountCallbacks.map(callback => callback({ selector, widget })));
});
}
returnCallbacks.forEach(callback => callback(result));
};
if (waitUntilEvent) {
await afterEvent({ func: start, ...waitUntilEvent });
} else {
await start();
if (waitUntilMessagingCondition === 'created') {
await testEnv.messagingCreatedPromise;
}
if (waitUntilMessagingCondition === 'initialized') {
await testEnv.messagingCreatedPromise;
await testEnv.modelManager.messaging.initializedPromise;
}
if (mountCallbacks.length > 0) {
await afterNextRender(async () => {
await Promise.all(mountCallbacks.map(callback => callback({ selector, widget })));
});
}
returnCallbacks.forEach(callback => callback(result));
await waitUntilEventPromise;
return result;
}
@@ -31,20 +31,15 @@ const DiscussWidget = AbstractAction.extend({
this.component = undefined;
this._lastPushStateActiveThread = null;
},
/**
* @override
*/
async willStart() {
await this._super(...arguments);
this.env = Component.env;
await this.env.messagingCreatedPromise;
const initActiveId = this.options.active_id ||
(this.action.context && this.action.context.active_id) ||
(this.action.params && this.action.params.default_active_id) ||
'mail.box_inbox';
this.discuss = this.env.messaging.discuss;
this.discuss.update({ initActiveId });
this.env.messagingCreatedPromise.then(() => {
const initActiveId = this.options.active_id ||
(this.action.context && this.action.context.active_id) ||
(this.action.params && this.action.params.default_active_id) ||
'mail.box_inbox';
this.discuss = this.env.messaging.discuss;
this.discuss.update({ initActiveId });
});
},
/**
* @override {web.AbstractAction}