[IMP] web: better looking cids in url
Before this commit, cids in the url (in the hash part) were separated by a comma, which was encoded by encodeURIComponent as it is not considered as a safe character, resulting into "%2C" appearing in the url in between company ids. This was kind of ugly and made the url a bit hard to read. This commit uses "-" as separator for cids, which is a safe characters [1] to use in the url and which is thus left untouched by encodeURIComponent. AL request. [1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#description closes odoo/odoo#136104 Related: odoo/enterprise#47723 Signed-off-by: Samuel Degueldre (sad) <sad@odoo.com>
This commit is contained in:
@@ -5,14 +5,19 @@ import { registry } from "@web/core/registry";
|
||||
import { session } from "@web/session";
|
||||
import { UPDATE_METHODS } from "@web/core/orm_service";
|
||||
|
||||
function parseCompanyIds(cidsFromHash) {
|
||||
const cids = [];
|
||||
if (typeof cidsFromHash === "string") {
|
||||
cids.push(...cidsFromHash.split(",").map(Number));
|
||||
} else if (typeof cidsFromHash === "number") {
|
||||
cids.push(cidsFromHash);
|
||||
const CIDS_HASH_SEPARATOR = "-";
|
||||
|
||||
function parseCompanyIds(cids, separator = ",") {
|
||||
if (typeof cids === "string") {
|
||||
return cids.split(separator).map(Number);
|
||||
} else if (typeof cids === "number") {
|
||||
return [cids];
|
||||
}
|
||||
return cids;
|
||||
return [];
|
||||
}
|
||||
|
||||
function formatCompanyIds(cids, separator = ",") {
|
||||
return cids.join(separator);
|
||||
}
|
||||
|
||||
function computeAllowedCompanyIds(cids) {
|
||||
@@ -34,30 +39,30 @@ export const companyService = {
|
||||
start(env, { user, router, cookie, action }) {
|
||||
let cids;
|
||||
if ("cids" in router.current.hash) {
|
||||
cids = parseCompanyIds(router.current.hash.cids);
|
||||
cids = parseCompanyIds(router.current.hash.cids, CIDS_HASH_SEPARATOR);
|
||||
} 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
|
||||
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);
|
||||
const cidsHash = formatCompanyIds(allowedCompanyIds, CIDS_HASH_SEPARATOR);
|
||||
router.replaceState({ cids: cidsHash }, { lock: true });
|
||||
cookie.setCookie("cids", formatCompanyIds(allowedCompanyIds));
|
||||
user.updateContext({ allowed_company_ids: allowedCompanyIds });
|
||||
|
||||
// reload the page if changes are being done to `res.company`
|
||||
@@ -92,15 +97,20 @@ export const companyService = {
|
||||
}
|
||||
} else if (mode === "loginto") {
|
||||
nextAvailableCompanies.splice(0, nextAvailableCompanies.length);
|
||||
nextAvailableCompanies.add(companyId)
|
||||
nextAvailableCompanies.add(companyId);
|
||||
}
|
||||
},
|
||||
logNextCompanies() {
|
||||
const next = nextAvailableCompanies.length ? nextAvailableCompanies : [allowedCompanyIds[0]]
|
||||
router.pushState({ cids: next }, { lock: true });
|
||||
cookie.setCookie("cids", next);
|
||||
const next = nextAvailableCompanies.length
|
||||
? nextAvailableCompanies
|
||||
: [allowedCompanyIds[0]];
|
||||
router.pushState(
|
||||
{ cids: formatCompanyIds(next, CIDS_HASH_SEPARATOR) },
|
||||
{ lock: true }
|
||||
);
|
||||
cookie.setCookie("cids", formatCompanyIds(next));
|
||||
browser.setTimeout(() => browser.location.reload()); // history.pushState is a little async
|
||||
}
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@@ -119,7 +119,7 @@ QUnit.module("MobileSwitchCompanyMenu", (hooks) => {
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 1);
|
||||
await prom;
|
||||
assert.verifySteps(["cids=1%2C2"]);
|
||||
assert.verifySteps(["cids=1-2"]);
|
||||
});
|
||||
|
||||
QUnit.test("can toggle multiple companies at once", async (assert) => {
|
||||
@@ -157,7 +157,7 @@ QUnit.module("MobileSwitchCompanyMenu", (hooks) => {
|
||||
|
||||
assert.verifySteps([]);
|
||||
await prom; // await toggle promise
|
||||
assert.verifySteps(["cids=2%2C3"]);
|
||||
assert.verifySteps(["cids=2-3"]);
|
||||
});
|
||||
|
||||
QUnit.test("single company selected: toggling it off will keep it", async (assert) => {
|
||||
@@ -231,7 +231,7 @@ QUnit.module("MobileSwitchCompanyMenu", (hooks) => {
|
||||
function onPushState(url) {
|
||||
assert.step(url.split("#")[1]);
|
||||
}
|
||||
Object.assign(browser.location, { hash: "cids=3%2C1" });
|
||||
Object.assign(browser.location, { hash: "cids=3-1" });
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
@@ -261,7 +261,7 @@ QUnit.module("MobileSwitchCompanyMenu", (hooks) => {
|
||||
function onPushState(url) {
|
||||
assert.step(url.split("#")[1]);
|
||||
}
|
||||
Object.assign(browser.location, { hash: "cids=2%2C3" });
|
||||
Object.assign(browser.location, { hash: "cids=2-3" });
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
|
||||
@@ -101,13 +101,15 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
|
||||
assert.containsN(target, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(target, "[data-company-id] .fa-square-o", 4);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll("[data-company-id] .toggle_company")].map(
|
||||
(el) => el.getAttribute('aria-checked')
|
||||
[...target.querySelectorAll("[data-company-id] .toggle_company")].map((el) =>
|
||||
el.getAttribute("aria-checked")
|
||||
),
|
||||
["true", "false", "false", "false", "false"]
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll("[data-company-id] .log_into")].map((el) => el.getAttribute('aria-pressed')),
|
||||
[...target.querySelectorAll("[data-company-id] .log_into")].map((el) =>
|
||||
el.getAttribute("aria-pressed")
|
||||
),
|
||||
["true", "false", "false", "false", "false"]
|
||||
);
|
||||
|
||||
@@ -123,17 +125,19 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
|
||||
assert.containsN(target, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(target, "[data-company-id] .fa-square-o", 3);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll("[data-company-id] .toggle_company")].map(
|
||||
(el) => el.getAttribute('aria-checked')
|
||||
[...target.querySelectorAll("[data-company-id] .toggle_company")].map((el) =>
|
||||
el.getAttribute("aria-checked")
|
||||
),
|
||||
["true", "true", "false", "false", "false"]
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll("[data-company-id] .log_into")].map((el) => el.getAttribute('aria-pressed')),
|
||||
[...target.querySelectorAll("[data-company-id] .log_into")].map((el) =>
|
||||
el.getAttribute("aria-pressed")
|
||||
),
|
||||
["true", "false", "false", "false", "false"]
|
||||
);
|
||||
await prom;
|
||||
assert.verifySteps(["cids=3%2C2"]);
|
||||
assert.verifySteps(["cids=3-2"]);
|
||||
});
|
||||
|
||||
QUnit.test("can toggle multiple companies at once", async (assert) => {
|
||||
@@ -176,7 +180,7 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
|
||||
|
||||
assert.verifySteps([]);
|
||||
await prom; // await toggle promise
|
||||
assert.verifySteps(["cids=2%2C1%2C4%2C5"]);
|
||||
assert.verifySteps(["cids=2-1-4-5"]);
|
||||
});
|
||||
|
||||
QUnit.test("single company selected: toggling it off will keep it", async (assert) => {
|
||||
@@ -260,7 +264,7 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
|
||||
function onPushState(url) {
|
||||
assert.step(url.split("#")[1]);
|
||||
}
|
||||
Object.assign(browser.location, { hash: "cids=3%2C1" });
|
||||
Object.assign(browser.location, { hash: "cids=3-1" });
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
|
||||
/**
|
||||
@@ -295,7 +299,7 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
|
||||
function onPushState(url) {
|
||||
assert.step(url.split("#")[1]);
|
||||
}
|
||||
Object.assign(browser.location, { hash: "cids=2%2C1" });
|
||||
Object.assign(browser.location, { hash: "cids=2-1" });
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
|
||||
/**
|
||||
@@ -321,7 +325,7 @@ QUnit.module("SwitchCompanyMenu", (hooks) => {
|
||||
*/
|
||||
await click(target.querySelectorAll(".log_into")[2]);
|
||||
assert.containsNone(target, ".dropdown-menu", "dropdown is directly closed");
|
||||
assert.verifySteps(["cids=1%2C4%2C5"]);
|
||||
assert.verifySteps(["cids=1-4-5"]);
|
||||
});
|
||||
|
||||
QUnit.test("companies can be logged in even if some toggled within delay", async (assert) => {
|
||||
|
||||
Reference in New Issue
Block a user