[FIX] web: company selector usability

Since 0eff29409d, the behavior was
unpredictable when clicking on multiple companies before a reload.

This simplifies the implementation and the behavior:
* the behavior is always the same even if there were already multiple
  companies selected: if one wants to add new companies they should use
  the check box instead.
* there is no more confusion due to the storage of the symetrical
  difference when toggling multiple companies and their children before
  the reload.

closes odoo/odoo#135086

X-original-commit: b07b30cd4b2a3e821a24761075ae0aecee332b14
Related: odoo/enterprise#47265
Signed-off-by: Bastien Fafchamps (bafa) <bafa@odoo.com>
Signed-off-by: William André (wan) <wan@odoo.com>
This commit is contained in:
william
2023-09-11 23:59:51 +00:00
parent 68d89150b1
commit dacbe1d496
4 changed files with 119 additions and 98 deletions
@@ -2,7 +2,6 @@
import { browser } from "@web/core/browser/browser";
import { registry } from "@web/core/registry";
import { symmetricalDifference } from "../core/utils/arrays";
import { session } from "@web/session";
import { UPDATE_METHODS } from "@web/core/orm_service";
@@ -39,15 +38,29 @@ export const companyService = {
} else if ("cids" in cookie.current) {
cids = parseCompanyIds(cookie.current.cids);
}
const availableCompanies = session.user_companies.allowed_companies;
const allowedCompanyIds = computeAllowedCompanyIds(cids);
const nextAvailableCompanies = allowedCompanyIds.slice(); // not using a Set because order is important
nextAvailableCompanies.add = (companyId) => {
if (!nextAvailableCompanies.includes(companyId)) {
nextAvailableCompanies.push(companyId);
availableCompanies[companyId].child_ids.map(nextAvailableCompanies.add);
}
}
nextAvailableCompanies.remove = (companyId) => {
if (nextAvailableCompanies.includes(companyId)) {
nextAvailableCompanies.splice(nextAvailableCompanies.indexOf(companyId), 1);
availableCompanies[companyId].child_ids.map(nextAvailableCompanies.remove);
}
}
const stringCIds = allowedCompanyIds.join(",");
router.replaceState({ cids: stringCIds }, { lock: true });
cookie.setCookie("cids", stringCIds);
user.updateContext({ allowed_company_ids: allowedCompanyIds });
const availableCompanies = session.user_companies.allowed_companies;
// reload the page if changes are being done to `res.company`
env.bus.addEventListener("RPC:RESPONSE", (ev) => {
const { data, error } = ev.detail;
const { model, method } = data.params;
@@ -57,8 +70,10 @@ export const companyService = {
}
}
});
return {
availableCompanies,
nextAvailableCompanies,
get allowedCompanyIds() {
return allowedCompanyIds.slice();
},
@@ -68,47 +83,24 @@ export const companyService = {
getCompany(companyId) {
return availableCompanies[companyId];
},
getAllChildren(companyId) {
return [
...availableCompanies[companyId].child_ids,
...availableCompanies[companyId].child_ids.map((child) => this.getAllChildren(child))
].flat()
},
getChildrenToToggle(companyId) {
const children = this.getAllChildren(companyId)
if ( allowedCompanyIds.includes(companyId) ) {
return children.filter((id) => allowedCompanyIds.includes(id))
} else {
return children.filter((id) => !allowedCompanyIds.includes(id))
}
},
setCompanies(mode, ...companyIds) {
// compute next company ids
let nextCompanyIds;
setCompanies(mode, companyId) {
if (mode === "toggle") {
nextCompanyIds = symmetricalDifference(allowedCompanyIds, companyIds);
} else if (mode === "loginto") {
const companyId = companyIds[0];
const children = this.getAllChildren(companyId);
if (allowedCompanyIds.length === 1) {
// 1 enabled company: stay in single company mode
nextCompanyIds = [companyId, ...children];
if (nextAvailableCompanies.includes(companyId)) {
nextAvailableCompanies.remove(companyId);
} else {
// multi company mode
nextCompanyIds = [
companyId,
...children,
...allowedCompanyIds.filter((id) => id !== companyId && !children.includes(id)),
];
nextAvailableCompanies.add(companyId);
}
} else if (mode === "loginto") {
nextAvailableCompanies.splice(0, nextAvailableCompanies.length);
nextAvailableCompanies.add(companyId)
}
nextCompanyIds = nextCompanyIds.length ? nextCompanyIds : [companyIds[0]];
// apply them
router.pushState({ cids: nextCompanyIds }, { lock: true });
cookie.setCookie("cids", nextCompanyIds);
browser.setTimeout(() => browser.location.reload()); // history.pushState is a little async
},
logNextCompanies() {
const next = nextAvailableCompanies.length ? nextAvailableCompanies : [allowedCompanyIds[0]]
router.pushState({ cids: next }, { lock: true });
cookie.setCookie("cids", next);
browser.setTimeout(() => browser.location.reload()); // history.pushState is a little async
}
};
},
};
@@ -5,13 +5,12 @@ import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { browser } from "@web/core/browser/browser";
import { symmetricalDifference } from "@web/core/utils/arrays";
import { Component, useState, reactive } from "@odoo/owl";
const store = reactive({
companiesToToggle: [],
toggleTimer: null,
nextAvailableCompanies: [],
});
@@ -21,25 +20,25 @@ export class SwitchCompanyItem extends Component {
this.store = useState(store);
}
logIntoCompany(companyId) {
browser.clearTimeout(this.store.toggleTimer);
this.companyService.setCompanies("loginto", companyId);
get selectedCompanies() {
this.store.nextAvailableCompanies; // check if the state changed
return this.companyService.nextAvailableCompanies;
}
get selectedCompanies() {
return symmetricalDifference(
this.companyService.allowedCompanyIds,
this.store.companiesToToggle,
);
logIntoCompany(companyId) {
this.companyService.setCompanies("loginto", companyId);
browser.clearTimeout(this.store.toggleTimer);
this.companyService.logNextCompanies();
}
toggleCompany(companyId) {
this.store.companiesToToggle = symmetricalDifference(this.store.companiesToToggle, [
companyId, ...this.companyService.getChildrenToToggle(companyId)
]);
this.companyService.setCompanies("toggle", companyId);
// trigger state change
this.store.nextAvailableCompanies = this.companyService.nextAvailableCompanies.slice();
browser.clearTimeout(this.store.toggleTimer);
this.store.toggleTimer = browser.setTimeout(() => {
this.companyService.setCompanies("toggle", ...this.store.companiesToToggle);
this.companyService.logNextCompanies();
}, this.constructor.toggleDelay);
}
}
@@ -56,7 +55,7 @@ export class SwitchCompanyMenu extends Component {
setup() {
this.companyService = useService("company");
this.store = useState(store);
this.store.companiesToToggle = [];
this.store.nextAvailableCompanies = [];
}
}
SwitchCompanyMenu.template = "web.SwitchCompanyMenu";