[IMP] web: Command Palette Footer Clickable
With this commit, it will be possible to click on the different namespace in the footer of the command palette to insert the namespace value directly into the searchValue. The purpose of this feature is to make it easier to discover how namespaces work. closes odoo/odoo#82773 Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
This commit is contained in:
@@ -82,7 +82,7 @@ export class CommandPalette extends Component {
|
||||
this.DefaultCommandItem = DefaultCommandItem;
|
||||
this.activeElement = useService("ui").activeElement;
|
||||
this.defaultDebounceSearch = debounce.apply(this, [this.search, 0]);
|
||||
useAutofocus();
|
||||
this.inputRef = useAutofocus();
|
||||
|
||||
useHotkey("Enter", () => this.executeSelectedCommand(), { bypassEditableProtection: true });
|
||||
useHotkey("ArrowUp", () => this.selectCommandAndScrollTo("PREV"), {
|
||||
@@ -267,6 +267,9 @@ export class CommandPalette extends Component {
|
||||
searchValue,
|
||||
activeElement: this.activeElement,
|
||||
});
|
||||
if (this.inputRef.el) {
|
||||
this.inputRef.el.focus();
|
||||
}
|
||||
}
|
||||
|
||||
debounceSearch(value) {
|
||||
@@ -299,5 +302,11 @@ export class CommandPalette extends Component {
|
||||
}
|
||||
return { namespace, searchValue };
|
||||
}
|
||||
|
||||
switchNamespace(namespace) {
|
||||
const searchValue = `${namespace}${this.clearSearchValue}`;
|
||||
this.state.searchValue = searchValue;
|
||||
this.debounceSearch(searchValue);
|
||||
}
|
||||
}
|
||||
CommandPalette.template = "web.CommandPalette";
|
||||
|
||||
@@ -122,6 +122,12 @@
|
||||
padding: 0.6rem 1.3em;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
||||
|
||||
.o_namespace:hover {
|
||||
color: $o-brand-primary;
|
||||
cursor: pointer;
|
||||
text-decoration: underline dotted;
|
||||
}
|
||||
|
||||
.o_promote {
|
||||
color: $o-brand-primary;
|
||||
font-weight: 900;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
|
||||
<div t-if="state.FooterComponent" class="o_command_palette_footer">
|
||||
<t t-component="state.FooterComponent"/>
|
||||
<t t-component="state.FooterComponent" switchNamespace="(namespace) => this.switchNamespace(namespace)"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -43,6 +43,10 @@ class DefaultFooter extends Component {
|
||||
.map((el) => ({ namespace: el[0], name: el[1].name }))
|
||||
.filter((el) => el.name);
|
||||
}
|
||||
|
||||
onClick(namespace) {
|
||||
this.props.switchNamespace(namespace);
|
||||
}
|
||||
}
|
||||
DefaultFooter.template = xml`
|
||||
<span>
|
||||
@@ -50,7 +54,9 @@ DefaultFooter.template = xml`
|
||||
<t t-foreach="elements" t-as="element" t-key="element.namespace">
|
||||
<t t-if="!(element_first || element_last)">, </t>
|
||||
<t t-if="element_last and !element_first"> and </t>
|
||||
<span t-esc="element.namespace" class='o_promote'/><t t-esc="element.name"/>
|
||||
<span class="o_namespace" t-on-click="() => this.onClick(element.namespace)">
|
||||
<span t-esc="element.namespace" class='o_promote'/><t t-esc="element.name"/>
|
||||
</span>
|
||||
</t>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@@ -490,6 +490,74 @@ QUnit.test("footer displays the right tips", async (assert) => {
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("namespaces display in the footer are still clickable", async (assert) => {
|
||||
const action = () => {};
|
||||
clearRegistryWithCleanup(commandProviderRegistry);
|
||||
commandProviderRegistry.add("@", {
|
||||
namespace: "@",
|
||||
provide: () => [
|
||||
{
|
||||
name: "Command@",
|
||||
action,
|
||||
},
|
||||
],
|
||||
});
|
||||
commandProviderRegistry.add("#", {
|
||||
namespace: "#",
|
||||
provide: () => [
|
||||
{
|
||||
name: "Command#",
|
||||
action,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const commandSetupRegistry = registry.category("command_setup");
|
||||
clearRegistryWithCleanup(commandSetupRegistry);
|
||||
commandSetupRegistry.add("default", {});
|
||||
commandSetupRegistry.add("@", {
|
||||
name: "users",
|
||||
});
|
||||
commandSetupRegistry.add("#", {
|
||||
name: "channels",
|
||||
});
|
||||
await mount(TestComponent, target, { env });
|
||||
|
||||
// Open palette
|
||||
triggerHotkey("control+k");
|
||||
await nextTick();
|
||||
assert.strictEqual(
|
||||
target.querySelector(".o_command_palette_footer").textContent,
|
||||
"TIP — search for @users and #channels"
|
||||
);
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_command")].map((el) => el.textContent),
|
||||
[]
|
||||
);
|
||||
|
||||
await click(target.querySelectorAll(".o_command_palette_footer .o_namespace")[0]);
|
||||
assert.strictEqual(target.querySelector(".o_command_palette_search input").value, "@");
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_command")].map((el) => el.textContent),
|
||||
["Command@"]
|
||||
);
|
||||
|
||||
await editSearchBar("Com");
|
||||
await click(target.querySelectorAll(".o_command_palette_footer .o_namespace")[1]);
|
||||
assert.strictEqual(target.querySelector(".o_command_palette_search input").value, "#Com");
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_command")].map((el) => el.textContent),
|
||||
["Command#"]
|
||||
);
|
||||
|
||||
await click(target.querySelectorAll(".o_command_palette_footer .o_namespace")[0]);
|
||||
assert.strictEqual(target.querySelector(".o_command_palette_search input").value, "@Com");
|
||||
assert.deepEqual(
|
||||
[...target.querySelectorAll(".o_command")].map((el) => el.textContent),
|
||||
["Command@"]
|
||||
);
|
||||
});
|
||||
|
||||
QUnit.test("defined multiple providers with the same namespace", async (assert) => {
|
||||
assert.expect(2);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user