[IMP] mail: delete time model, add clock and clock watcher models

The Time model is deleted and replaced with the new Clock model. The
differences are that there can be several clocks, whereas Time was a
singleton, and that a clock must define the frequency at which it
updates.

The new model ClockWatcher is added to model a record that makes use of
a clock. This is currently useful for the clocks to set or clear intervals
as needed.

closes odoo/odoo#86219

Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
This commit is contained in:
Louis Wicket (wil)
2022-03-14 10:38:11 +00:00
parent 18ed0e3be2
commit 24a19a10c9
8 changed files with 170 additions and 48 deletions
@@ -74,7 +74,7 @@ registerModel({
if (!this.activity.dateDeadline) {
return clear();
}
const today = moment(this.messaging.time.currentDateEveryMinute.getTime()).startOf('day');
const today = moment(this.clockWatcher.clock.date.getTime()).startOf('day');
const momentDeadlineDate = moment(auto_str_to_date(this.activity.dateDeadline));
// true means no rounding
const diff = momentDeadlineDate.diff(today, 'days', true);
@@ -167,6 +167,15 @@ registerModel({
assignedUserText: attr({
compute: '_computeAssignedUserText',
}),
clockWatcher: one('ClockWatcher', {
default: insertAndReplace({
clock: insertAndReplace({
frequency: 60 * 1000,
}),
}),
inverse: 'activityViewOwner',
isCausal: true,
}),
/**
* Compute the label for "when" the activity is due.
*/
@@ -0,0 +1,75 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr, many } from '@mail/model/model_field';
import { OnChange } from '@mail/model/model_onchange';
/**
* Models a record that provides the current date, updated at a given frequency.
*/
registerModel({
name: 'Clock',
identifyingFields: ['frequency'],
lifecycleHooks: {
_willDelete() {
this.messaging.browser.clearInterval(this.tickInterval);
},
},
recordMethods: {
/**
* @private
* @returns {integer}
*/
_computeTickInterval() {
return this.messaging.browser.setInterval(this._onInterval, this.frequency);
},
/**
* @private
*/
_onChangeWatchers() {
if (this.watchers.length === 0) {
this.delete();
}
},
/**
* @private
*/
_onInterval() {
this.update({ date: new Date() });
},
},
fields: {
/**
* A Date object set at the current date, updated at every tick.
*/
date: attr({
default: new Date(),
}),
/**
* An integer representing the frequency in milliseconds at which `date`
* must be recomputed.
*/
frequency: attr({
readonly: true,
required: true,
}),
tickInterval: attr({
compute: '_computeTickInterval',
}),
/**
* The records that are making use of this clock.
*
* The clock self-destructs when there are no more watchers.
*/
watchers: many('ClockWatcher', {
inverse: 'clock',
isCausal: true,
}),
},
onChanges: [
new OnChange({
dependencies: ['watchers'],
methodName: '_onChangeWatchers',
}),
],
});
@@ -0,0 +1,22 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { one } from '@mail/model/model_field';
/**
* Models a record that makes use of a clock.
*/
registerModel({
name: 'ClockWatcher',
identifyingFields: [['activityViewOwner']],
fields: {
activityViewOwner: one('ActivityView', {
inverse: 'clockWatcher',
readonly: true,
}),
clock: one('Clock', {
inverse: 'watchers',
required: true,
}),
},
});
@@ -375,12 +375,6 @@ registerModel({
* Mailbox Starred.
*/
starred: one('Thread'),
time: one('Time', {
default: insertAndReplace(),
isCausal: true,
readonly: true,
required: true,
}),
userSetting: one('UserSetting', {
isCausal: true,
}),
@@ -1,41 +0,0 @@
/** @odoo-module **/
import { registerModel } from '@mail/model/model_core';
import { attr } from '@mail/model/model_field';
registerModel({
name: 'Time',
identifyingFields: ['messaging'],
lifecycleHooks: {
_willDelete() {
clearInterval(this.everyMinuteIntervalId);
},
},
recordMethods: {
/**
* @private
* @returns {number}
*/
_computeEveryMinuteIntervalId() {
return setInterval(this._onEveryMinuteTimeout, 60 * 1000);
},
/**
* @private
*/
_onEveryMinuteTimeout() {
this.update({ currentDateEveryMinute: new Date() });
},
},
fields: {
/**
* Contains a Date object that is set to the current time, and is
* (re-)computed every minute.
*/
currentDateEveryMinute: attr({
default: new Date(),
}),
everyMinuteIntervalId: attr({
compute: '_computeEveryMinuteIntervalId',
}),
},
});
@@ -0,0 +1,42 @@
/** @odoo-module **/
import { insertAndReplace } from '@mail/model/model_field_command';
import { afterEach, beforeEach, start } from '@mail/utils/test_utils';
QUnit.module('mail', {}, function () {
QUnit.module('clock_model_tests', {
async beforeEach() {
await beforeEach(this);
this.start = async params => {
const res = await start({ ...params, data: this.data });
const { apps, env, widget } = res;
this.apps = apps;
this.env = env;
this.widget = widget;
return res;
};
},
afterEach() {
afterEach(this);
},
});
QUnit.test('Deleting all the watchers of a clock should result in the deletion of the clock itself.', async function (assert) {
assert.expect(1);
await this.start();
const watcher = this.messaging.models['ClockWatcher'].insert({
clock: insertAndReplace({ frequency: 180 * 1000 }),
qunitTestOwner: insertAndReplace(),
});
const { clock } = watcher;
watcher.delete();
assert.notOk(
clock.exists(),
"deleting all the watchers of a clock should result in the deletion of the clock itself."
);
});
});
@@ -0,0 +1,17 @@
/** @odoo-module **/
import { addFields, patchIdentifyingFields } from '@mail/model/model_core';
import { one } from '@mail/model/model_field';
// ensure that the model definition is loaded before the patch
import '@mail/models/clock_watcher/clock_watcher';
patchIdentifyingFields('ClockWatcher', identifyingFields => {
identifyingFields[0].push('qunitTestOwner');
});
addFields('ClockWatcher', {
qunitTestOwner: one('QUnitTest', {
inverse: 'clockWatcher',
readonly: true,
}),
});
+4
View File
@@ -7,6 +7,10 @@ registerModel({
name: 'QUnitTest',
identifyingFields: [], // singleton acceptable (only one test at a time)
fields: {
clockWatcher: one('ClockWatcher', {
inverse: 'qunitTestOwner',
isCausal: true,
}),
composer: one('Composer', {
isCausal: true,
}),