Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions addons/im_livechat/static/src/core/public_web/upgrade_19_1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { upgrade_19_1 } from "@mail/core/common/upgrade/upgrade_19_1";

upgrade_19_1.add("discuss_sidebar_category_folded_im_livechat.category_default", {
key: "DiscussAppCategory,im_livechat.category_default:is_open",
value: false,
});
45 changes: 45 additions & 0 deletions addons/im_livechat/static/tests/upgrade_19_1.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { defineLivechatModels } from "@im_livechat/../tests/livechat_test_helpers";

import { DiscussAppCategory } from "@mail/discuss/core/public_web/discuss_app/discuss_app_category_model";
import { makeRecordFieldLocalId } from "@mail/model/misc";
import { toRawValue } from "@mail/utils/common/local_storage";
import { contains, openDiscuss, start, startServer } from "@mail/../tests/mail_test_helpers";

import { beforeEach, describe, expect, test } from "@odoo/hoot";

import { Command, serverState } from "@web/../tests/web_test_helpers";

describe.current.tags("desktop");
defineLivechatModels();

beforeEach(() => {
serverState.serverVersion = [99, 9]; // high version so following upgrades keep good working of feature
});

test("category 'Livechat' is folded", async () => {
const pyEnv = await startServer();
const guestId = pyEnv["mail.guest"].create({ name: "Visitor" });
pyEnv["discuss.channel"].create({
channel_member_ids: [
Command.create({
livechat_member_type: "agent",
partner_id: serverState.partnerId,
}),
Command.create({ guest_id: guestId, livechat_member_type: "visitor" }),
],
channel_type: "livechat",
livechat_operator_id: serverState.partnerId,
});
localStorage.setItem("discuss_sidebar_category_folded_im_livechat.category_default", "true");
await start();
await openDiscuss();
await contains(".o-mail-DiscussSidebarCategory:contains('Livechat') .oi.oi-chevron-right");
const defaultLivechat_is_open = makeRecordFieldLocalId(
DiscussAppCategory.localId("im_livechat.category_default"),
"is_open"
);
expect(localStorage.getItem(defaultLivechat_is_open)).toBe(toRawValue(false));
expect(
localStorage.getItem("discuss_sidebar_category_folded_im_livechat.category_default")
).toBe(null);
});
68 changes: 3 additions & 65 deletions addons/mail/static/src/core/common/settings_model.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,9 @@ import { fields, Record } from "@mail/model/export";
import { debounce } from "@web/core/utils/timing";
import { rpc } from "@web/core/network/rpc";

const MESSAGE_SOUND = "mail.user_setting.message_sound";

export class Settings extends Record {
id;

static new() {
const record = super.new(...arguments);
record.onStorage = record.onStorage.bind(record);
browser.addEventListener("storage", record.onStorage);
return record;
}

setup() {
super.setup();
this.saveVoiceThresholdDebounce = debounce(() => {
Expand All @@ -30,11 +21,6 @@ export class Settings extends Record {
this._loadLocalSettings();
}

delete() {
browser.removeEventListener("storage", this.onStorage);
super.delete(...arguments);
}

// Notification settings
/**
* @type {"mentions"|"all"|"no_notif"}
Expand All @@ -44,33 +30,8 @@ export class Settings extends Record {
return this.channel_notifications === false ? "mentions" : this.channel_notifications;
},
});
messageSound = fields.Attr(true, {
compute() {
return browser.localStorage.getItem(MESSAGE_SOUND) !== "false";
},
/** @this {import("models").Settings} */
onUpdate() {
if (this.messageSound) {
browser.localStorage.removeItem(MESSAGE_SOUND);
} else {
browser.localStorage.setItem(MESSAGE_SOUND, "false");
}
},
});
useCallAutoFocus = fields.Attr(true, {
/** @this {import("models").Settings} */
compute() {
return !browser.localStorage.getItem("mail_user_setting_disable_call_auto_focus");
},
/** @this {import("models").Settings} */
onUpdate() {
if (this.useCallAutoFocus) {
browser.localStorage.removeItem("mail_user_setting_disable_call_auto_focus");
return;
}
browser.localStorage.setItem("mail_user_setting_disable_call_auto_focus", "true");
},
});
messageSound = fields.Attr(true, { localStorage: true });
useCallAutoFocus = fields.Attr(true, { localStorage: true });

// Voice settings
// DeviceId of the audio input selected by the user
Expand All @@ -91,19 +52,7 @@ export class Settings extends Record {
backgroundBlurAmount = 10;
edgeBlurAmount = 10;
showOnlyVideo = false;
useBlur = fields.Attr(false, {
compute() {
return browser.localStorage.getItem("mail_user_setting_use_blur") === "true";
},
/** @this {import("models").Settings} */
onUpdate() {
if (this.useBlur) {
browser.localStorage.setItem("mail_user_setting_use_blur", "true");
} else {
browser.localStorage.removeItem("mail_user_setting_use_blur");
}
},
});
useBlur = fields.Attr(false, { localStorage: true });
blurPerformanceWarning = fields.Attr(false, {
compute() {
const rtc = this.store.rtc;
Expand Down Expand Up @@ -388,9 +337,6 @@ export class Settings extends Record {
this.backgroundBlurAmount = backgroundBlurAmount ? parseInt(backgroundBlurAmount) : 10;
const edgeBlurAmount = browser.localStorage.getItem("mail_user_setting_edge_blur_amount");
this.edgeBlurAmount = edgeBlurAmount ? parseInt(edgeBlurAmount) : 10;
this.useCallAutoFocus = !browser.localStorage.getItem(
"mail_user_setting_disable_call_auto_focus"
);
}
/**
* @private
Expand Down Expand Up @@ -425,14 +371,6 @@ export class Settings extends Record {
{ guest_id: guestId }
);
}
onStorage(ev) {
if (ev.key === MESSAGE_SOUND) {
this.messageSound = ev.newValue !== "false";
}
if (ev.key === "mail_user_setting_use_blur") {
this.useBlur = ev.newValue === "true";
}
}
/**
* @private
*/
Expand Down
2 changes: 1 addition & 1 deletion addons/mail/static/src/core/common/store_service.js
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ export class Store extends BaseStore {
Store.register();

export const storeService = {
dependencies: ["bus_service", "im_status", "ui", "popover"],
dependencies: ["bus_service", "im_status", "ui", "popover", "discuss.upgrade"],
/**
* @param {import("@web/env").OdooEnv} env
* @param {import("services").ServiceFactories} services
Expand Down
30 changes: 30 additions & 0 deletions addons/mail/static/src/core/common/upgrade/upgrade_19_1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { addUpgrade } from "@mail/core/common/upgrade/upgrade_helpers";

/** @typedef {import("@mail/core/common/upgrade/upgrade_helpers").UpgradeFnParam} UpgradeFnParam */
/** @typedef {import("@mail/core/common/upgrade/upgrade_helpers").UpgradeFnReturn} UpgradeFnReturn */

export const upgrade_19_1 = {
/**
* @param {string} key
* @param {((param: UpgradeFnParam) => UpgradeFnReturn)|UpgradeFnReturn} upgrade
* @returns {UpgradeFnReturn}
*/
add(key, upgrade) {
return addUpgrade({ key, version: "19.1", upgrade });
},
};

upgrade_19_1.add("mail.user_setting.message_sound", {
key: "Settings,undefined:messageSound",
value: false,
});

upgrade_19_1.add("mail_user_setting_disable_call_auto_focus", {
key: "Settings,undefined:useCallAutoFocus",
value: false,
});

upgrade_19_1.add("mail_user_setting_use_blur", {
key: "Settings,undefined:useBlur",
value: true,
});
122 changes: 122 additions & 0 deletions addons/mail/static/src/core/common/upgrade/upgrade_helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { getCurrentLocalStorageVersion, LocalStorageEntry } from "@mail/utils/common/local_storage";
import { parseVersion } from "@mail/utils/common/misc";
import { registry } from "@web/core/registry";

/**
* @typedef {Object} UpgradeData
* @property {string} version
* @property {string} key
* @property {((param: UpgradeFnParam) => UpgradeFnReturn)|UpgradeFnReturn} upgrade
*/
/**
* @typedef {Object} UpgradeDataWithoutVersion
* @property {string} key
* @property {((param: UpgradeFnParam) => UpgradeFnReturn)|UpgradeFnReturn} upgrade
*/
/**
* @typedef {Object} UpgradeFnParam
* @property {string} key
* @property {any} value
*/
/**
* @typedef {Object} UpgradeFnReturn
* @property {string} key
* @property {any} value
*/

/**
* Register a `key` and `upgrade` function for a `version` of local storage.
*
* When there's request to upgrade a local storage
*
* Example:
* - we have versions 19.1, 19.3, and 20.0.
* - define upgrade function with 19.1 is to upgrade to 19.1
* - define ugrade function with 20.0 is to upgrade to 20.0
*
* Upgrades are applied in sequence, i.e.:
* - if version is 20.0 and local storage data are in version 0, this will apply upgrade to 19.1, then to 19.3 and finally to 20.0.
* - if version is 20.0 and local storage data are in version 19.1, this will apply upgrade to 19.3 and finally to 20.0.
* - if version is 20.0 and local storage data are in version 19.2, this will apply upgrade to 19.3 and finally to 20.0.
* - if version is 20.0 and local storage data are in version 20.0, this will not upgrade data.
*
* @param {UpgradeData} param0
*/
export function addUpgrade({ version, key, upgrade }) {
/** @type {Map<string, Function[]>} */
const map = getUpgradeMap();
if (!map.has(version)) {
map.set(version, new Map());
}
map.get(version).set(key, { version, key, upgrade });
}

/** @param {string} version */
export function upgradeFrom(version) {
const orderedUpgradeList = Array.from(getUpgradeMap().entries())
.filter(
([v]) =>
!parseVersion(v).isLowerThan(version) &&
!parseVersion(getCurrentLocalStorageVersion()).isLowerThan(v)
)
.sort(([v1], [v2]) => (parseVersion(v1).isLowerThan(v2) ? -1 : 1));
for (const [, keyMap] of orderedUpgradeList) {
for (const upgradeData of keyMap.values()) {
applyUpgrade(upgradeData);
}
}
}

const upgradeRegistry = registry.category("discuss.upgrade");
upgradeRegistry.add(null, new Map());

/**
* A Map of version numbers to a Map of keys and upgrade functions.
* Basically:
*
* Map: {
* "19.1": {
* key_1: upgradeData_1,
* key_2: upgradeData_2,
* },
* "19.2": {
* key_3: upgradeData_3,
* key_4: upgradeData_4,
* ...
* },
* ...
* }
*
* To upgrade a key in a given version, find the key in version
* and applyUpgrade using upgradeData to upgrade with new key, value and version.
*
* @return {Map<string, Map<string, UpgradeData>>}
*/
function getUpgradeMap() {
return upgradeRegistry.get(null);
}

/**
* Upgrade local storage using `upgrade` data.
* i.e. call `upgradeData.upgrade` to get new key and value.
*
* @param {UpgradeData} upgradeData
*/
function applyUpgrade(upgradeData) {
const oldEntry = new LocalStorageEntry(upgradeData.key);
const parsed = oldEntry.parse();
const oldValue = parsed ?? oldEntry.get();
if (
oldValue === null ||
(parsed && parsed.version && parseVersion(upgradeData.version).isLowerThan(parsed.version))
) {
return; // could not upgrade (cannot parse or more recent version)
}
const { key, value } =
typeof upgradeData.upgrade === "function"
? upgradeData.upgrade({ key: upgradeData.key, value: oldValue })
: upgradeData.upgrade;
oldEntry.remove();
const newEntry = new LocalStorageEntry(key);
newEntry.set(value, upgradeData.version);
}
20 changes: 20 additions & 0 deletions addons/mail/static/src/core/common/upgrade/upgrade_service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { registry } from "@web/core/registry";
import { upgradeFrom } from "./upgrade_helpers";
import { getCurrentLocalStorageVersion, LocalStorageEntry } from "@mail/utils/common/local_storage";
import { parseVersion } from "@mail/utils/common/misc";

export const discussUpgradeService = {
dependencies: [],
start() {
const lse = new LocalStorageEntry("discuss.upgrade.version");
const parsed = lse.parse();
const oldVersion = parsed?.version ?? "1.0";
const currentVersion = getCurrentLocalStorageVersion();
lse.set(true, currentVersion);
if (parseVersion(oldVersion).isLowerThan(currentVersion)) {
upgradeFrom(oldVersion);
}
},
};

registry.category("services").add("discuss.upgrade", discussUpgradeService);
Loading