diff --git a/addons/web/static/src/core/commands/command_palette.js b/addons/web/static/src/core/commands/command_palette.js index b8349269cd7..607df17fbdb 100644 --- a/addons/web/static/src/core/commands/command_palette.js +++ b/addons/web/static/src/core/commands/command_palette.js @@ -3,7 +3,7 @@ import { Dialog } from "@web/core/dialog/dialog"; import { useHotkey } from "@web/core/hotkeys/hotkey_hook"; import { _t } from "@web/core/l10n/translation"; -import { KeepLast } from "@web/core/utils/concurrency"; +import { KeepLast, Race } from "@web/core/utils/concurrency"; import { useAutofocus, useService } from "@web/core/utils/hooks"; import { scrollTo } from "@web/core/utils/scrolling"; import { fuzzyLookup } from "@web/core/utils/search"; @@ -107,6 +107,7 @@ export class CommandPalette extends Component { } this.keyId = 1; + this.race = new Race(); this.keepLast = new KeepLast(); this._sessionId = CommandPalette.lastSessionId++; this.DefaultCommandItem = DefaultCommandItem; @@ -181,7 +182,7 @@ export class CommandPalette extends Component { const { namespace, searchValue } = this.processSearchValue(config.searchValue || ""); this.switchNamespace(namespace); - await this.search(searchValue); + await this.race.add(this.search(searchValue)); } /** diff --git a/addons/web/static/tests/core/commands/command_service_tests.js b/addons/web/static/tests/core/commands/command_service_tests.js index 8753e9326f5..d0a82929753 100644 --- a/addons/web/static/tests/core/commands/command_service_tests.js +++ b/addons/web/static/tests/core/commands/command_service_tests.js @@ -15,6 +15,7 @@ import { click, destroy, getFixture, + makeDeferred, mount, nextTick, patchWithCleanup, @@ -1267,3 +1268,63 @@ QUnit.test("uses openPalette to modify the config used by the command palette", ); assert.deepEqual(target.querySelector(".o_command_palette_search input").value, "Command"); }); + +QUnit.test( + "ensure that calling openPalette multiple times successfully loads the last config for the command palette", + async (assert) => { + const providePromise1 = makeDeferred(); + const providePromise2 = makeDeferred(); + const action = () => {}; + + await mount(TestComponent, target, { env }); + + const provide = [ + async () => { + await providePromise1; + return [ + { + name: "Command1", + action, + }, + ]; + }, + async () => { + await providePromise2; + return [ + { + name: "Command2", + action, + }, + ]; + }, + ]; + const configCustom1 = { + searchValue: "Command", + providers: [{ provide: provide[0] }], + }; + const configCustom2 = { + searchValue: "Command", + providers: [{ provide: provide[1] }], + }; + + env.services.command.openPalette(configCustom1); + await nextTick(); + assert.containsNone(target, ".o_command_palette"); + env.services.command.openPalette(configCustom2); + await nextTick(); + assert.containsNone(target, ".o_command_palette"); + providePromise1.resolve(); + await nextTick(); + // First config should not be loaded since a second config was sent. + assert.containsNone(target, ".o_command_palette"); + providePromise2.resolve(); + await nextTick(); + // Second config should be loaded properly. + assert.containsN(target, ".o_command", 1); + assert.deepEqual( + [...target.querySelectorAll(".o_command span:first-child")].map((el) => el.textContent), + ["Command2"] + ); + assert.deepEqual(target.querySelector(".o_command_palette_search input").value, "Command"); + } +);