[REF] web: remove LegacyComponent
Before this commit, components used `el` and `trigger` but this works thanks to LegacyComponent. LegacyComponent has been introduced to ease the transition from owl 1 to owl 2. This commit replaces the uses of `el` by `useRef` and `trigger` by adding callback in props. Without these owl 1 features, components no longer need to extend LegacyComponent. This commit also adapts the tests to use `getFixture` instead of `el`. closes odoo/odoo#85903 Related: odoo/enterprise#25032 Signed-off-by: Samuel Degueldre <sad@odoo.com> Co-authored-by: Aaron Bohy <aab@odoo.com> Co-authored-by: Simon Genin (ges) <ges@odoo.com> Co-authored-by: luvi <luvi@odoo.com> Co-authored-by: Jorge Pinna Puissant <jpp@odoo.com>
This commit is contained in:
co-authored by
Aaron Bohy
Simon Genin
luvi
Jorge Pinna Puissant
parent
3ff07b1a01
commit
8a5721bc7d
@@ -15,8 +15,8 @@
|
||||
<div class="o_command_category">
|
||||
<t t-foreach="category.commands" t-as="command" t-key="command.keyId">
|
||||
<t t-set="commandIndex" t-value="state.commands.indexOf(command)" />
|
||||
<div t-attf-id="o_command_{{commandIndex}}" class="o_command" t-att-class="{ focused: state.selectedCommand === command }" t-on-click="() => this.onCommandClicked(commandIndex)" t-on-mouseenter="() => this.onCommandMouseEnter(commandIndex)" t-on-close="() => this.props.closeMe()" t-on-execute-command="() => this.executeCommand(command)">
|
||||
<t t-component="command.Component || DefaultCommandItem" name="command.name" searchValue="clearSearchValue" t-props="command.props">
|
||||
<div t-attf-id="o_command_{{commandIndex}}" class="o_command" t-att-class="{ focused: state.selectedCommand === command }" t-on-click="() => this.onCommandClicked(commandIndex)" t-on-mouseenter="() => this.onCommandMouseEnter(commandIndex)" t-on-close="() => this.props.closeMe()">
|
||||
<t t-component="command.Component || DefaultCommandItem" name="command.name" searchValue="clearSearchValue" t-props="command.props" executeCommand="() => this.executeCommand(command)">
|
||||
<t t-set-slot="name">
|
||||
<span class="o_command_name">
|
||||
<t t-foreach="command.splitName" t-as="name" t-key="name_index">
|
||||
|
||||
@@ -7,18 +7,17 @@ import { registry } from "@web/core/registry";
|
||||
import { capitalize } from "@web/core/utils/strings";
|
||||
import { getVisibleElements } from "@web/core/utils/ui";
|
||||
import { DefaultCommandItem } from "./command_palette";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
const commandSetupRegistry = registry.category("command_setup");
|
||||
commandSetupRegistry.add("default", {
|
||||
emptyMessage: _lt("No command found"),
|
||||
});
|
||||
|
||||
export class HotkeyCommandItem extends LegacyComponent {
|
||||
export class HotkeyCommandItem extends Component {
|
||||
setup() {
|
||||
useHotkey(this.props.hotkey, () => {
|
||||
this.trigger("execute-command");
|
||||
});
|
||||
useHotkey(this.props.hotkey, this.props.executeCommand);
|
||||
}
|
||||
|
||||
getKeysToPress(command) {
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
import { localization } from "@web/core/l10n/localization";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useAutofocus } from "@web/core/utils/hooks";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const {
|
||||
Component,
|
||||
onMounted,
|
||||
onWillUpdateProps,
|
||||
onWillUnmount,
|
||||
@@ -49,8 +49,9 @@ const luxonFormatToMomentFormat = (format) => {
|
||||
* stringified since tempusdominus only works with moment objects.
|
||||
* @extends Component
|
||||
*/
|
||||
export class DatePicker extends LegacyComponent {
|
||||
export class DatePicker extends Component {
|
||||
setup() {
|
||||
this.root = useRef("root");
|
||||
this.inputRef = useRef("input");
|
||||
this.state = useState({ warning: false });
|
||||
|
||||
@@ -68,9 +69,9 @@ export class DatePicker extends LegacyComponent {
|
||||
}
|
||||
|
||||
onMounted() {
|
||||
window.$(this.el).on("show.datetimepicker", () => this.inputRef.el.select());
|
||||
window.$(this.el).on("hide.datetimepicker", () => this.onDateChange());
|
||||
window.$(this.el).on("error.datetimepicker", () => false); // Ignores datepicker errors
|
||||
window.$(this.root.el).on("show.datetimepicker", () => this.inputRef.el.select());
|
||||
window.$(this.root.el).on("hide.datetimepicker", () => this.onDateChange());
|
||||
window.$(this.root.el).on("error.datetimepicker", () => false); // Ignores datepicker errors
|
||||
|
||||
this.bootstrapDateTimePicker(this.props);
|
||||
this.updateInput();
|
||||
@@ -91,7 +92,7 @@ export class DatePicker extends LegacyComponent {
|
||||
}
|
||||
|
||||
onWillUnmount() {
|
||||
window.$(this.el).off(); // Removes all jQuery events
|
||||
window.$(this.root.el).off(); // Removes all jQuery events
|
||||
|
||||
this.bootstrapDateTimePicker("destroy");
|
||||
}
|
||||
@@ -169,7 +170,7 @@ export class DatePicker extends LegacyComponent {
|
||||
}
|
||||
commandOrParams = params;
|
||||
}
|
||||
window.$(this.el).datetimepicker(commandOrParams);
|
||||
window.$(this.root.el).datetimepicker(commandOrParams);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
|
||||
<t t-name="web.DatePicker" owl="1">
|
||||
<div class="o_datepicker" aria-atomic="true" t-att-id="datePickerId" data-target-input="nearest">
|
||||
<div class="o_datepicker" aria-atomic="true" t-att-id="datePickerId" data-target-input="nearest" t-ref="root">
|
||||
<input type="text"
|
||||
class="o_datepicker_input o_input datetimepicker-input"
|
||||
t-att-name="props.name"
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
import { useHotkey } from "@web/core/hotkeys/hotkey_hook";
|
||||
import { useActiveElement } from "../ui/ui_service";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { useRef, useChildSubEnv, xml } = owl;
|
||||
const { Component, useRef, useChildSubEnv, xml } = owl;
|
||||
|
||||
export class Dialog extends LegacyComponent {
|
||||
export class Dialog extends Component {
|
||||
setup() {
|
||||
if (this.constructor === Dialog) {
|
||||
throw new Error(
|
||||
|
||||
@@ -4,9 +4,9 @@ import { useBus, useService } from "@web/core/utils/hooks";
|
||||
import { usePosition } from "../position/position_hook";
|
||||
import { useDropdownNavigation } from "./dropdown_navigation_hook";
|
||||
import { localization } from "../l10n/localization";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const {
|
||||
Component,
|
||||
EventBus,
|
||||
onWillStart,
|
||||
useEffect,
|
||||
@@ -40,7 +40,7 @@ export const DROPDOWN = Symbol("Dropdown");
|
||||
/**
|
||||
* @extends Component
|
||||
*/
|
||||
export class Dropdown extends LegacyComponent {
|
||||
export class Dropdown extends Component {
|
||||
setup() {
|
||||
this.state = useState({
|
||||
open: this.props.startOpen,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
import { DROPDOWN } from "./dropdown";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
@@ -11,7 +12,7 @@ const ParentClosingMode = {
|
||||
AllParents: "all",
|
||||
};
|
||||
|
||||
export class DropdownItem extends LegacyComponent {
|
||||
export class DropdownItem extends Component {
|
||||
/**
|
||||
* Tells the parent dropdown that an item was selected and closes the
|
||||
* parent(s) dropdown according the the parentClosingMode prop.
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { browser } from "@web/core/browser/browser";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { useEffect, useExternalListener } = owl;
|
||||
const { Component, useEffect, useExternalListener, useState } = owl;
|
||||
|
||||
/**
|
||||
* @typedef Common
|
||||
@@ -34,15 +33,16 @@ const { useEffect, useExternalListener } = owl;
|
||||
* importing this file. The usual way to do that would be to use the effect
|
||||
* service (by triggering the 'show_effect' event)
|
||||
*/
|
||||
export class RainbowMan extends LegacyComponent {
|
||||
export class RainbowMan extends Component {
|
||||
setup() {
|
||||
useExternalListener(document.body, "click", this.closeRainbowMan);
|
||||
this.state = useState({ isFading: false });
|
||||
this.delay = RainbowMan.rainbowFadeouts[this.props.fadeout];
|
||||
if (this.delay) {
|
||||
useEffect(
|
||||
() => {
|
||||
const timeout = browser.setTimeout(() => {
|
||||
this.el.classList.add("o_reward_fading");
|
||||
this.state.isFading = true;
|
||||
}, this.delay);
|
||||
return () => browser.clearTimeout(timeout);
|
||||
},
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.RainbowMan" owl="1">
|
||||
<div class="o_reward" t-on-animationend="onAnimationEnd">
|
||||
<div class="o_reward" t-att-class="{ o_reward_fading: state.isFading }" t-on-animationend="onAnimationEnd">
|
||||
<svg class="o_reward_rainbow" viewBox="0 0 340 180">
|
||||
<path d="M270,170a100,100,0,0,0-200,0" style="stroke:#FF9E80;"/>
|
||||
<path d="M290,170a120,120,0,0,0-240,0" style="stroke:#FFE57F;"/>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { useRef } = owl;
|
||||
const { Component, useRef } = owl;
|
||||
|
||||
/**
|
||||
* Custom file input
|
||||
@@ -23,7 +22,7 @@ const { useRef } = owl;
|
||||
* @param {string} [props.multi_upload=false] Whether the input should allow
|
||||
* to upload multiple files at once.
|
||||
*/
|
||||
export class FileInput extends LegacyComponent {
|
||||
export class FileInput extends Component {
|
||||
setup() {
|
||||
this.http = useService("http");
|
||||
this.fileInputRef = useRef("file-input");
|
||||
@@ -58,7 +57,7 @@ export class FileInput extends LegacyComponent {
|
||||
if (parsedFileData.error) {
|
||||
throw new Error(parsedFileData.error);
|
||||
}
|
||||
this.trigger("uploaded", { files: parsedFileData });
|
||||
this.props.onUpload(parsedFileData);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.FileInput" owl="1">
|
||||
<span class="o_file_input" aria-atomic="true" t-on-uploaded="(ev) => props.onUpload(ev.detail.files)">
|
||||
<span class="o_file_input" aria-atomic="true">
|
||||
<span class="o_file_input_trigger" t-on-click.prevent="onTriggerClicked">
|
||||
<t t-slot="default">
|
||||
<button class="btn btn-primary">Choose File</button>
|
||||
|
||||
@@ -18,7 +18,6 @@ Popover.defaultProps = {
|
||||
position: "bottom",
|
||||
};
|
||||
Popover.props = {
|
||||
close: { type: Function },
|
||||
popoverClass: {
|
||||
optional: true,
|
||||
type: String,
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
<t t-name="web.PopoverWowl" owl="1">
|
||||
<div role="tooltip" class="o_popover"
|
||||
t-att-class="props.popoverClass"
|
||||
t-on-popover-compute="compute"
|
||||
t-on-popover-closed="props.close"
|
||||
t-ref="popper"
|
||||
>
|
||||
<t t-slot="default" />
|
||||
|
||||
@@ -21,12 +21,19 @@ class PopoverController extends Component {
|
||||
|
||||
get popoverProps() {
|
||||
return {
|
||||
close: this.props.close,
|
||||
target: this.target,
|
||||
position: this.props.position,
|
||||
popoverClass: this.props.popoverClass,
|
||||
};
|
||||
}
|
||||
|
||||
get popoverComponentProps() {
|
||||
return {
|
||||
close: this.props.close,
|
||||
...this.props.props,
|
||||
};
|
||||
}
|
||||
|
||||
get target() {
|
||||
if (typeof this.props.target === "string") {
|
||||
return document.querySelector(this.props.target);
|
||||
@@ -56,7 +63,7 @@ PopoverController.defaultProps = {
|
||||
};
|
||||
PopoverController.template = xml/*xml*/ `
|
||||
<Popover t-props="popoverProps">
|
||||
<t t-component="props.Component" t-props="props.props"/>
|
||||
<t t-component="props.Component" t-props="popoverComponentProps"/>
|
||||
</Popover>
|
||||
`;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ const { Component } = owl;
|
||||
export class Tooltip extends Component {}
|
||||
Tooltip.template = "web.Tooltip";
|
||||
Tooltip.props = {
|
||||
close: Function,
|
||||
tooltip: { type: String, optional: true },
|
||||
template: { type: String, optional: true },
|
||||
info: { optional: true },
|
||||
|
||||
@@ -83,6 +83,7 @@ export function useBus(bus, eventName, callback) {
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* The useListener hook offers an alternative to Owl's classical event
|
||||
* registration mechanism (with attribute 't-on-eventName' in xml).
|
||||
*
|
||||
|
||||
@@ -228,19 +228,21 @@ odoo.define('web.OwlDialog', function (require) {
|
||||
this.displayed.splice(this.displayed.indexOf(dialog), 1);
|
||||
// Activate last dialog and update body class
|
||||
const lastDialog = this.displayed[this.displayed.length - 1];
|
||||
let modalEl;
|
||||
if (lastDialog) {
|
||||
if (lastDialog.el) {
|
||||
// legacy dialog
|
||||
lastDialog.el.focus();
|
||||
modalEl = lastDialog.$modal[0];
|
||||
} else if (lastDialog.modalRef) {
|
||||
// Owl 2 / Wowl dialogs (because of legacy_dialogs.js patch on Dialog)
|
||||
lastDialog.modalRef.el.focus();
|
||||
modalEl = lastDialog.modalRef.el;
|
||||
} else {
|
||||
// Owl dialog | LegacyAdaptedDialog
|
||||
lastDialog.dialogRef.el.focus();
|
||||
modalEl = lastDialog.dialogRef.el;
|
||||
}
|
||||
const modalEl = lastDialog.modalRef ?
|
||||
// Owl dialog | LegacyAdaptedDialog
|
||||
lastDialog.modalRef.el :
|
||||
// Legacy dialog
|
||||
lastDialog.$modal[0];
|
||||
modalEl.classList.remove('o_inactive_modal');
|
||||
modalEl.setAttribute("tabindex", "-1");
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* This component SHOULD NOT be used!
|
||||
@@ -41,11 +39,8 @@ export class LegacyComponent extends owl.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (hasOwnProperty.call(bdom, "component")) {
|
||||
return bdom.component.el;
|
||||
} else {
|
||||
return bdom.firstNode();
|
||||
}
|
||||
const el = (bdom.component && bdom.component.el) || bdom.firstNode();
|
||||
return el.nodeType === Node.ELEMENT_NODE ? el : null;
|
||||
}
|
||||
/**
|
||||
* Add a new method to owl Components to ensure that no performed RPC is
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { Dropdown } from "@web/core/dropdown/dropdown";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { useState } = owl;
|
||||
const { Component, useState } = owl;
|
||||
|
||||
export class CustomGroupByItem extends LegacyComponent {
|
||||
export class CustomGroupByItem extends Component {
|
||||
setup() {
|
||||
this.state = useState({});
|
||||
if (this.props.fields.length) {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
import { ControlPanel } from "@web/search/control_panel/control_panel";
|
||||
import { SearchPanel } from "@web/search/search_panel/search_panel";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { Component } = owl;
|
||||
|
||||
/**
|
||||
* @param {Object} params
|
||||
@@ -16,7 +17,7 @@ export const extractLayoutComponents = (params) => {
|
||||
};
|
||||
};
|
||||
|
||||
export class Layout extends LegacyComponent {
|
||||
export class Layout extends Component {
|
||||
setup() {
|
||||
const { display = {} } = this.env.searchModel || {};
|
||||
this.components = extractLayoutComponents(this.env.config);
|
||||
|
||||
@@ -6,19 +6,19 @@ import { registry } from "@web/core/registry";
|
||||
import { KeepLast } from "@web/core/utils/concurrency";
|
||||
import { useAutofocus, useBus, useService } from "@web/core/utils/hooks";
|
||||
import { fuzzyTest } from "@web/core/utils/search";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { useExternalListener, useState } = owl;
|
||||
const { Component, useExternalListener, useRef, useState } = owl;
|
||||
const parsers = registry.category("parsers");
|
||||
|
||||
const CHAR_FIELDS = ["char", "html", "many2many", "many2one", "one2many", "text"];
|
||||
|
||||
let nextItemId = 1;
|
||||
|
||||
export class SearchBar extends LegacyComponent {
|
||||
export class SearchBar extends Component {
|
||||
setup() {
|
||||
this.fields = this.env.searchModel.searchViewFields;
|
||||
this.searchItems = this.env.searchModel.getSearchItems((f) => f.type === "field");
|
||||
this.root = useRef("root");
|
||||
|
||||
// core state
|
||||
this.state = useState({
|
||||
@@ -221,7 +221,7 @@ export class SearchBar extends LegacyComponent {
|
||||
* @param {number} [index]
|
||||
*/
|
||||
focusFacet(index) {
|
||||
const facets = this.el.getElementsByClassName("o_searchview_facet");
|
||||
const facets = this.root.el.getElementsByClassName("o_searchview_facet");
|
||||
if (facets.length) {
|
||||
if (!index) {
|
||||
facets[facets.length - 1].focus();
|
||||
@@ -295,7 +295,7 @@ export class SearchBar extends LegacyComponent {
|
||||
break;
|
||||
}
|
||||
case "ArrowRight": {
|
||||
const facets = this.el.getElementsByClassName("o_searchview_facet");
|
||||
const facets = this.root.el.getElementsByClassName("o_searchview_facet");
|
||||
if (facetIndex === facets.length - 1) {
|
||||
this.inputRef.el.focus();
|
||||
} else {
|
||||
@@ -441,7 +441,7 @@ export class SearchBar extends LegacyComponent {
|
||||
* @param {MouseEvent} ev
|
||||
*/
|
||||
onWindowClick(ev) {
|
||||
if (this.items.length && !this.el.contains(ev.target)) {
|
||||
if (this.items.length && !this.root.el.contains(ev.target)) {
|
||||
this.resetState();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@
|
||||
</t>
|
||||
|
||||
<t t-name="web.SearchBar" owl="1">
|
||||
<div class="o_cp_searchview" role="search">
|
||||
<div class="o_cp_searchview" role="search" t-ref="root">
|
||||
<div class="o_searchview" role="search" aria-autocomplete="list">
|
||||
<i class="o_searchview_icon oi oi-search"
|
||||
role="img"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { onMounted, onWillStart, onWillUpdateProps, useState } = owl;
|
||||
const { Component, onMounted, onWillStart, onWillUpdateProps, useRef, useState } = owl;
|
||||
|
||||
/**
|
||||
* Search panel
|
||||
@@ -13,12 +11,13 @@ const { onMounted, onWillStart, onWillUpdateProps, useState } = owl;
|
||||
* values (categories or ungrouped filters) or groups of values (grouped filters).
|
||||
* Its state is directly affected by its model (@see SearchModel).
|
||||
*/
|
||||
export class SearchPanel extends LegacyComponent {
|
||||
export class SearchPanel extends Component {
|
||||
setup() {
|
||||
this.state = useState({
|
||||
active: {},
|
||||
expanded: {},
|
||||
});
|
||||
this.root = useRef("root");
|
||||
this.scrollTop = 0;
|
||||
this.hasImportedState = false;
|
||||
|
||||
@@ -33,7 +32,7 @@ export class SearchPanel extends LegacyComponent {
|
||||
onMounted(() => {
|
||||
this.updateGroupHeadersChecked();
|
||||
if (this.hasImportedState) {
|
||||
this.el.scroll({ top: this.scrollTop });
|
||||
this.root.el.scroll({ top: this.scrollTop });
|
||||
}
|
||||
});
|
||||
|
||||
@@ -58,7 +57,7 @@ export class SearchPanel extends LegacyComponent {
|
||||
exportState() {
|
||||
const exported = {
|
||||
expanded: this.state.expanded,
|
||||
scrollTop: this.el.scrollTop,
|
||||
scrollTop: this.root.el.scrollTop,
|
||||
};
|
||||
return JSON.stringify(exported);
|
||||
}
|
||||
@@ -182,7 +181,7 @@ export class SearchPanel extends LegacyComponent {
|
||||
* headers according to the state of their values.
|
||||
*/
|
||||
updateGroupHeadersChecked() {
|
||||
const groups = this.el.querySelectorAll(":scope .o_search_panel_filter_group");
|
||||
const groups = this.root.el.querySelectorAll(":scope .o_search_panel_filter_group");
|
||||
for (const group of groups) {
|
||||
const header = group.querySelector(":scope .o_search_panel_group_header input");
|
||||
const vals = [...group.querySelectorAll(":scope .o_search_panel_filter_value input")];
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<t t-name="web.SearchPanel" owl="1">
|
||||
<div class="o_search_panel" t-att-class="env.searchModel.searchPanelInfo.className">
|
||||
<div class="o_search_panel" t-att-class="env.searchModel.searchPanelInfo.className" t-ref="root">
|
||||
<section t-foreach="sections" t-as="section" t-key="section.id"
|
||||
t-attf-class="o_search_panel_section o_search_panel_{{ section.type }}"
|
||||
>
|
||||
|
||||
@@ -3,14 +3,13 @@
|
||||
import { useBus, useService } from "@web/core/utils/hooks";
|
||||
import { SearchModel } from "@web/search/search_model";
|
||||
import { CallbackRecorder, useSetupAction } from "@web/webclient/actions/action_hook";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { onWillStart, onWillUpdateProps, toRaw, useSubEnv } = owl;
|
||||
const { Component, onWillStart, onWillUpdateProps, toRaw, useSubEnv } = owl;
|
||||
|
||||
export const SEARCH_KEYS = ["comparison", "context", "domain", "groupBy", "orderBy"];
|
||||
const OTHER_SEARCH_KEYS = ["irFilters", "searchViewArch", "searchViewFields", "searchViewId"];
|
||||
|
||||
export class WithSearch extends LegacyComponent {
|
||||
export class WithSearch extends Component {
|
||||
setup() {
|
||||
this.Component = this.props.Component;
|
||||
|
||||
|
||||
@@ -7,9 +7,8 @@ import { SEP } from "./graph_model";
|
||||
import { sortBy } from "@web/core/utils/arrays";
|
||||
import { useAssets } from "@web/core/assets";
|
||||
import { renderToString } from "@web/core/utils/render";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { onWillUnmount, useEffect, useRef } = owl;
|
||||
const { Component, onWillUnmount, useEffect, useRef } = owl;
|
||||
|
||||
const NO_DATA = _lt("No data");
|
||||
|
||||
@@ -39,10 +38,11 @@ function shortenLabel(label) {
|
||||
return shortLabel;
|
||||
}
|
||||
|
||||
export class GraphRenderer extends LegacyComponent {
|
||||
export class GraphRenderer extends Component {
|
||||
setup() {
|
||||
this.model = this.props.model;
|
||||
|
||||
this.rootRef = useRef("root");
|
||||
this.canvasRef = useRef("canvas");
|
||||
this.containerRef = useRef("container");
|
||||
|
||||
@@ -99,16 +99,16 @@ export class GraphRenderer extends LegacyComponent {
|
||||
*/
|
||||
customTooltip(data, metaData, tooltipModel) {
|
||||
const { measure, measures, disableLinking, mode } = metaData;
|
||||
this.el.style.cursor = "";
|
||||
this.rootRef.el.style.cursor = "";
|
||||
this.removeTooltips();
|
||||
if (tooltipModel.opacity === 0 || tooltipModel.dataPoints.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (!disableLinking && mode !== "line") {
|
||||
this.el.style.cursor = "pointer";
|
||||
this.rootRef.el.style.cursor = "pointer";
|
||||
}
|
||||
const chartAreaTop = this.chart.chartArea.top;
|
||||
const viewContentTop = this.el.getBoundingClientRect().top;
|
||||
const viewContentTop = this.rootRef.el.getBoundingClientRect().top;
|
||||
const innerHTML = renderToString("web.GraphRenderer.CustomTooltip", {
|
||||
maxWidth: getMaxWidth(this.chart.chartArea),
|
||||
measure: measures[measure].string,
|
||||
@@ -548,7 +548,7 @@ export class GraphRenderer extends LegacyComponent {
|
||||
if (this.legendTooltip || text === fullText) {
|
||||
return;
|
||||
}
|
||||
const viewContentTop = this.el.getBoundingClientRect().top;
|
||||
const viewContentTop = this.rootRef.el.getBoundingClientRect().top;
|
||||
const legendTooltip = Object.assign(document.createElement("div"), {
|
||||
className: "o_tooltip_legend",
|
||||
innerText: fullText,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
</t>
|
||||
|
||||
<t t-name="web.GraphRenderer" owl="1">
|
||||
<div t-att-class="'o_graph_renderer o_renderer ' + props.class">
|
||||
<div t-att-class="'o_graph_renderer o_renderer ' + props.class" t-ref="root">
|
||||
<div class="o_graph_canvas_container" t-ref="container">
|
||||
<canvas t-ref="canvas" />
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useDebugCategory } from "@web/core/debug/debug_context";
|
||||
import { useSetupAction } from "@web/webclient/actions/action_hook";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { useListener, useService } from "@web/core/utils/hooks";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { evaluateExpr } from "@web/core/py_js/py";
|
||||
|
||||
const { useComponent, xml } = owl;
|
||||
@@ -53,7 +53,6 @@ export function useViewArch(arch, params = {}) {
|
||||
* @param {Function} [params.reload] The function to execute to reload, if a button has data-reload-on-close
|
||||
*/
|
||||
export function useActionLinks({ resModel, reload }) {
|
||||
const selector = `a[type="action"]`;
|
||||
const component = useComponent();
|
||||
const keepLast = component.env.keepLast;
|
||||
|
||||
@@ -128,5 +127,10 @@ export function useActionLinks({ resModel, reload }) {
|
||||
checkAndCollapseBootstrap(target);
|
||||
}
|
||||
|
||||
useListener("click", selector, handler);
|
||||
return (ev) => {
|
||||
const a = ev.target.closest(`a[type="action"]`);
|
||||
if (a && ev.currentTarget.contains(a)) {
|
||||
handler(ev);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,16 +3,15 @@
|
||||
import { loadAssets } from "@web/core/assets";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { useActionLinks } from "@web/views/helpers/view_hook";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { markup, onWillStart, xml } = owl;
|
||||
const { Component, markup, onWillStart, xml } = owl;
|
||||
|
||||
export class OnboardingBanner extends LegacyComponent {
|
||||
export class OnboardingBanner extends Component {
|
||||
setup() {
|
||||
this.rpc = useService("rpc");
|
||||
this.user = useService("user");
|
||||
const resModel = "searchModel" in this.env ? this.env.searchModel.resModel : undefined;
|
||||
useActionLinks({
|
||||
this.handleActionLinks = useActionLinks({
|
||||
resModel,
|
||||
reload: async () => {
|
||||
this.bannerHTML = await this.loadBanner(this.env.config.bannerRoute);
|
||||
@@ -53,5 +52,5 @@ export class OnboardingBanner extends LegacyComponent {
|
||||
}
|
||||
}
|
||||
|
||||
OnboardingBanner.template = xml`<div class="w-100" t-out="bannerHTML"/>`;
|
||||
OnboardingBanner.template = xml`<div class="w-100" t-on-click="handleActionLinks" t-out="bannerHTML"/>`;
|
||||
OnboardingBanner.props = {};
|
||||
|
||||
@@ -5,16 +5,16 @@ import { localization } from "@web/core/l10n/localization";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { PivotGroupByMenu } from "@web/views/pivot/pivot_group_by_menu";
|
||||
import fieldUtils from "web.field_utils";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { onWillUpdateProps } = owl;
|
||||
const { Component, onWillUpdateProps, useRef } = owl;
|
||||
const formatterRegistry = registry.category("formatters");
|
||||
|
||||
export class PivotRenderer extends LegacyComponent {
|
||||
export class PivotRenderer extends Component {
|
||||
setup() {
|
||||
this.model = this.props.model;
|
||||
this.table = this.model.getTable();
|
||||
this.l10n = localization;
|
||||
this.tableRef = useRef("table");
|
||||
|
||||
onWillUpdateProps(this.onWillUpdateProps);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ export class PivotRenderer extends LegacyComponent {
|
||||
}
|
||||
index += 1; // row groupbys column
|
||||
}
|
||||
this.el
|
||||
this.tableRef.el
|
||||
.querySelectorAll("td:nth-child(" + (index + 1) + ")")
|
||||
.forEach((elt) => elt.classList.add("o_cell_hover"));
|
||||
}
|
||||
@@ -144,7 +144,7 @@ export class PivotRenderer extends LegacyComponent {
|
||||
* Remove the hover on the columns.
|
||||
*/
|
||||
onMouseLeave() {
|
||||
this.el
|
||||
this.tableRef.el
|
||||
.querySelectorAll(".o_cell_hover")
|
||||
.forEach((elt) => elt.classList.remove("o_cell_hover"));
|
||||
}
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
<t t-name="web.PivotRenderer" owl="1">
|
||||
<div class="o_pivot table-responsive">
|
||||
|
||||
<table class="table-hover table table-sm table-bordered bg-white" t-att-class="{
|
||||
o_enable_linking: !model.metaData.disableLinking,
|
||||
o_sample_data_disabled: model.useSampleModel,
|
||||
}">
|
||||
<table
|
||||
class="table-hover table table-sm table-bordered bg-white"
|
||||
t-att-class="{
|
||||
o_enable_linking: !model.metaData.disableLinking,
|
||||
o_sample_data_disabled: model.useSampleModel,
|
||||
}"
|
||||
t-ref="table"
|
||||
>
|
||||
<thead>
|
||||
<tr t-foreach="table.headers" t-as="row" t-key="'header_' + row_index">
|
||||
<t t-foreach="row" t-as="cell" t-key="'header_row_' + cell_index">
|
||||
|
||||
@@ -8,9 +8,8 @@ import { deepCopy } from "@web/core/utils/objects";
|
||||
import { extractLayoutComponents } from "@web/search/layout";
|
||||
import { WithSearch } from "@web/search/with_search/with_search";
|
||||
import { useActionLinks } from "@web/views/helpers/view_hook";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { onWillUpdateProps, onWillStart, toRaw, useSubEnv } = owl;
|
||||
const { Component, onWillUpdateProps, onWillStart, toRaw, useSubEnv } = owl;
|
||||
const viewRegistry = registry.category("views");
|
||||
|
||||
/** @typedef {Object} Config
|
||||
@@ -125,7 +124,7 @@ const STANDARD_PROPS = [
|
||||
"searchModel",
|
||||
];
|
||||
|
||||
export class View extends LegacyComponent {
|
||||
export class View extends Component {
|
||||
setup() {
|
||||
const { arch, fields, resModel, searchViewArch, searchViewFields, type } = this.props;
|
||||
|
||||
@@ -153,7 +152,7 @@ export class View extends LegacyComponent {
|
||||
},
|
||||
});
|
||||
|
||||
useActionLinks({ resModel });
|
||||
this.handleActionLinks = useActionLinks({ resModel });
|
||||
|
||||
onWillStart(this.onWillStart);
|
||||
onWillUpdateProps(this.onWillUpdateProps);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.View" owl="1">
|
||||
<div t-attf-class="o_action o_view_controller o_{{env.config.viewType}}_view">
|
||||
<div t-attf-class="o_action o_view_controller o_{{env.config.viewType}}_view" t-on-click="handleActionLinks">
|
||||
<WithSearch t-props="withSearchProps"/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
@@ -6,9 +6,8 @@ import { useService, useBus } from "@web/core/utils/hooks";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { debounce } from "@web/core/utils/timing";
|
||||
import { ErrorHandler } from "@web/core/utils/components";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { onWillDestroy, useExternalListener, useEffect, useRef } = owl;
|
||||
const { Component, onWillDestroy, useExternalListener, useEffect, useRef } = owl;
|
||||
const systrayRegistry = registry.category("systray");
|
||||
|
||||
const getBoundingClientRect = Element.prototype.getBoundingClientRect;
|
||||
@@ -31,11 +30,12 @@ MenuDropdown.props.xmlid = {
|
||||
optional: true,
|
||||
};
|
||||
|
||||
export class NavBar extends LegacyComponent {
|
||||
export class NavBar extends Component {
|
||||
setup() {
|
||||
this.currentAppSectionsExtra = [];
|
||||
this.actionService = useService("action");
|
||||
this.menuService = useService("menu");
|
||||
this.root = useRef("root");
|
||||
this.appSubMenus = useRef("appSubMenus");
|
||||
const debouncedAdapt = debounce(this.adapt.bind(this), 250);
|
||||
onWillDestroy(() => debouncedAdapt.cancel());
|
||||
@@ -95,7 +95,8 @@ export class NavBar extends LegacyComponent {
|
||||
* By the end of this method another render may occur depending on the adaptation result.
|
||||
*/
|
||||
async adapt() {
|
||||
if (!this.el) {
|
||||
if (!this.root.el) {
|
||||
/** @todo do we still need this check? */
|
||||
// currently, the promise returned by 'render' is resolved at the end of
|
||||
// the rendering even if the component has been destroyed meanwhile, so we
|
||||
// may get here and have this.el unset
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.NavBar" owl="1">
|
||||
<header>
|
||||
<header class="o_navbar" t-ref="root">
|
||||
<nav
|
||||
class="o_main_navbar"
|
||||
data-command-category="navbar"
|
||||
|
||||
@@ -6,11 +6,10 @@ 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 { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { useState } = owl;
|
||||
const { Component, useState } = owl;
|
||||
|
||||
export class SwitchCompanyMenu extends LegacyComponent {
|
||||
export class SwitchCompanyMenu extends Component {
|
||||
setup() {
|
||||
this.companyService = useService("company");
|
||||
this.currentCompany = this.companyService.currentCompany;
|
||||
|
||||
@@ -8,9 +8,8 @@ import { Dialog } from "@web/core/dialog/dialog";
|
||||
import { makeTestEnv } from "../helpers/mock_env";
|
||||
import { click, destroy, getFixture, mount } from "../helpers/utils";
|
||||
import { makeFakeDialogService } from "../helpers/mock_services";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { useEffect, useState, xml } = owl;
|
||||
const { Component, useEffect, useState, xml } = owl;
|
||||
const serviceRegistry = registry.category("services");
|
||||
let parent;
|
||||
let target;
|
||||
@@ -95,7 +94,7 @@ QUnit.module("Components", (hooks) => {
|
||||
|
||||
QUnit.test("simple rendering with two dialogs", async function (assert) {
|
||||
assert.expect(3);
|
||||
class Parent extends LegacyComponent {}
|
||||
class Parent extends Component {}
|
||||
Parent.template = xml`
|
||||
<div>
|
||||
<SimpleDialog title="'First Title'">
|
||||
@@ -124,7 +123,7 @@ QUnit.module("Components", (hooks) => {
|
||||
assert.expect(3);
|
||||
const env = await makeTestEnv();
|
||||
class MyDialog extends SimpleDialog {}
|
||||
class Parent extends LegacyComponent {
|
||||
class Parent extends Component {
|
||||
close() {
|
||||
assert.step("close");
|
||||
}
|
||||
@@ -148,7 +147,7 @@ QUnit.module("Components", (hooks) => {
|
||||
const env = await makeTestEnv();
|
||||
assert.expect(3);
|
||||
class MyDialog extends SimpleDialog {}
|
||||
class Parent extends LegacyComponent {
|
||||
class Parent extends Component {
|
||||
close() {
|
||||
assert.step("close");
|
||||
}
|
||||
@@ -181,7 +180,7 @@ QUnit.module("Components", (hooks) => {
|
||||
<button class="btn btn-primary">The Second Button</button>
|
||||
</div>
|
||||
`;
|
||||
class Parent extends LegacyComponent {
|
||||
class Parent extends Component {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.state = useState({
|
||||
@@ -203,7 +202,7 @@ QUnit.module("Components", (hooks) => {
|
||||
|
||||
QUnit.test("embed an arbitrary component in a dialog is possible", async function (assert) {
|
||||
assert.expect(6);
|
||||
class SubComponent extends LegacyComponent {
|
||||
class SubComponent extends Component {
|
||||
_onClick() {
|
||||
assert.step("subcomponent-clicked");
|
||||
this.props.onClicked();
|
||||
@@ -212,7 +211,7 @@ QUnit.module("Components", (hooks) => {
|
||||
SubComponent.template = xml`
|
||||
<div class="o_subcomponent" t-esc="props.text" t-on-click="_onClick"/>
|
||||
`;
|
||||
class Parent extends LegacyComponent {
|
||||
class Parent extends Component {
|
||||
_onSubcomponentClicked() {
|
||||
assert.step("message received by parent");
|
||||
}
|
||||
@@ -234,7 +233,7 @@ QUnit.module("Components", (hooks) => {
|
||||
|
||||
QUnit.test("dialog without header/footer", async function (assert) {
|
||||
assert.expect(4);
|
||||
class Parent extends LegacyComponent {}
|
||||
class Parent extends Component {}
|
||||
Parent.template = xml`
|
||||
<SimpleDialog renderHeader="false" renderFooter="false"/>
|
||||
`;
|
||||
@@ -249,7 +248,7 @@ QUnit.module("Components", (hooks) => {
|
||||
|
||||
QUnit.test("dialog size can be chosen", async function (assert) {
|
||||
assert.expect(5);
|
||||
class Parent extends LegacyComponent {}
|
||||
class Parent extends Component {}
|
||||
Parent.template = xml`
|
||||
<div>
|
||||
<SimpleDialog contentClass="'xl'" size="'modal-xl'"/>
|
||||
@@ -281,7 +280,7 @@ QUnit.module("Components", (hooks) => {
|
||||
|
||||
QUnit.test("dialog can be rendered on fullscreen", async function (assert) {
|
||||
assert.expect(2);
|
||||
class Parent extends LegacyComponent {}
|
||||
class Parent extends Component {}
|
||||
Parent.template = xml`
|
||||
<div><SimpleDialog fullscreen="true"/></div>
|
||||
`;
|
||||
@@ -294,7 +293,7 @@ QUnit.module("Components", (hooks) => {
|
||||
|
||||
QUnit.test("can be the UI active element", async function (assert) {
|
||||
assert.expect(3);
|
||||
class Parent extends LegacyComponent {
|
||||
class Parent extends Component {
|
||||
setup() {
|
||||
this.ui = useService("ui");
|
||||
this.modal = null;
|
||||
|
||||
@@ -15,13 +15,14 @@ import {
|
||||
nextTick,
|
||||
patchWithCleanup,
|
||||
} from "../../helpers/utils";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { markup, xml } = owl;
|
||||
const { Component, markup, xml } = owl;
|
||||
const serviceRegistry = registry.category("services");
|
||||
const mainComponentRegistry = registry.category("main_components");
|
||||
|
||||
class Parent extends LegacyComponent {
|
||||
let target;
|
||||
|
||||
class Parent extends Component {
|
||||
setup() {
|
||||
this.EffectContainer = mainComponentRegistry.get("EffectContainer");
|
||||
this.NotificationContainer = mainComponentRegistry.get("NotificationContainer");
|
||||
@@ -36,7 +37,6 @@ Parent.template = xml`
|
||||
|
||||
async function makeParent() {
|
||||
const env = await makeTestEnv({ serviceRegistry });
|
||||
const target = getFixture();
|
||||
const parent = await mount(Parent, target, { env });
|
||||
return parent;
|
||||
}
|
||||
@@ -56,6 +56,8 @@ QUnit.module("Effect Service", (hooks) => {
|
||||
serviceRegistry.add("effect", effectService);
|
||||
serviceRegistry.add("notification", notificationService);
|
||||
serviceRegistry.add("localization", makeFakeLocalizationService());
|
||||
|
||||
target = getFixture();
|
||||
});
|
||||
|
||||
QUnit.test("effect service displays a rainbowman by default", async function (assert) {
|
||||
@@ -64,8 +66,8 @@ QUnit.module("Effect Service", (hooks) => {
|
||||
await nextTick();
|
||||
execRegisteredTimeouts();
|
||||
|
||||
assert.containsOnce(parent.el, ".o_reward");
|
||||
assert.strictEqual(parent.el.querySelector(".o_reward").innerText, "Well Done!");
|
||||
assert.containsOnce(target, ".o_reward");
|
||||
assert.strictEqual(target.querySelector(".o_reward").innerText, "Well Done!");
|
||||
});
|
||||
|
||||
QUnit.test("rainbowman effect with show_effect: false", async function (assert) {
|
||||
@@ -76,8 +78,8 @@ QUnit.module("Effect Service", (hooks) => {
|
||||
await nextTick();
|
||||
execRegisteredTimeouts();
|
||||
|
||||
assert.containsNone(parent.el, ".o_reward");
|
||||
assert.containsOnce(parent.el, ".o_notification");
|
||||
assert.containsNone(target, ".o_reward");
|
||||
assert.containsOnce(target, ".o_notification");
|
||||
});
|
||||
|
||||
QUnit.test("rendering a rainbowman destroy after animation", async function (assert) {
|
||||
@@ -86,17 +88,17 @@ QUnit.module("Effect Service", (hooks) => {
|
||||
await nextTick();
|
||||
execRegisteredTimeouts();
|
||||
|
||||
assert.containsOnce(parent, ".o_reward");
|
||||
assert.containsOnce(parent, ".o_reward_rainbow");
|
||||
assert.containsOnce(target, ".o_reward");
|
||||
assert.containsOnce(target, ".o_reward_rainbow");
|
||||
assert.strictEqual(
|
||||
parent.el.querySelector(".o_reward_msg_content").innerHTML,
|
||||
target.querySelector(".o_reward_msg_content").innerHTML,
|
||||
"<div>Congrats!</div>"
|
||||
);
|
||||
|
||||
const ev = new AnimationEvent("animationend", { animationName: "reward-fading-reverse" });
|
||||
parent.el.querySelector(".o_reward").dispatchEvent(ev);
|
||||
target.querySelector(".o_reward").dispatchEvent(ev);
|
||||
await nextTick();
|
||||
assert.containsNone(parent, ".o_reward");
|
||||
assert.containsNone(target, ".o_reward");
|
||||
});
|
||||
|
||||
QUnit.test("rendering a rainbowman destroy on click", async function (assert) {
|
||||
@@ -106,11 +108,11 @@ QUnit.module("Effect Service", (hooks) => {
|
||||
await nextTick();
|
||||
execRegisteredTimeouts();
|
||||
|
||||
assert.containsOnce(parent.el, ".o_reward");
|
||||
assert.containsOnce(parent.el, ".o_reward_rainbow");
|
||||
assert.containsOnce(target, ".o_reward");
|
||||
assert.containsOnce(target, ".o_reward_rainbow");
|
||||
|
||||
await click(parent.el);
|
||||
assert.containsNone(parent, ".o_reward");
|
||||
await click(target);
|
||||
assert.containsNone(target, ".o_reward");
|
||||
});
|
||||
|
||||
QUnit.test("rendering a rainbowman with an escaped message", async function (assert) {
|
||||
@@ -120,18 +122,15 @@ QUnit.module("Effect Service", (hooks) => {
|
||||
await nextTick();
|
||||
execRegisteredTimeouts();
|
||||
|
||||
assert.containsOnce(parent.el, ".o_reward");
|
||||
assert.containsOnce(parent.el, ".o_reward_rainbow");
|
||||
assert.strictEqual(
|
||||
parent.el.querySelector(".o_reward_msg_content").textContent,
|
||||
"Congrats!"
|
||||
);
|
||||
assert.containsOnce(target, ".o_reward");
|
||||
assert.containsOnce(target, ".o_reward_rainbow");
|
||||
assert.strictEqual(target.querySelector(".o_reward_msg_content").textContent, "Congrats!");
|
||||
});
|
||||
|
||||
QUnit.test("rendering a rainbowman with a custom component", async function (assert) {
|
||||
assert.expect(2);
|
||||
const props = { foo: "bar" };
|
||||
class Custom extends LegacyComponent {
|
||||
class Custom extends Component {
|
||||
setup() {
|
||||
assert.deepEqual(this.props, props, "should have received these props");
|
||||
}
|
||||
@@ -143,7 +142,7 @@ QUnit.module("Effect Service", (hooks) => {
|
||||
await nextTick();
|
||||
execRegisteredTimeouts();
|
||||
assert.strictEqual(
|
||||
parent.el.querySelector(".o_reward_msg_content").innerHTML,
|
||||
target.querySelector(".o_reward_msg_content").innerHTML,
|
||||
`<div class="custom">foo is bar</div>`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -20,9 +20,8 @@ import {
|
||||
makeFakeRPCService,
|
||||
} from "../../helpers/mock_services";
|
||||
import { makeDeferred, nextTick, patchWithCleanup } from "../../helpers/utils";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
const errorDialogRegistry = registry.category("error_dialogs");
|
||||
const errorHandlerRegistry = registry.category("error_handlers");
|
||||
const serviceRegistry = registry.category("services");
|
||||
@@ -84,7 +83,7 @@ QUnit.test(
|
||||
"handle custom RPC_ERROR of type='server' and associated custom dialog class",
|
||||
async (assert) => {
|
||||
assert.expect(2);
|
||||
class CustomDialog extends LegacyComponent {}
|
||||
class CustomDialog extends Component {}
|
||||
CustomDialog.template = xml`<RPCErrorDialog title="'Strange Error'"/>`;
|
||||
CustomDialog.components = { RPCErrorDialog };
|
||||
const error = new RPCError();
|
||||
@@ -120,10 +119,10 @@ QUnit.test(
|
||||
"handle normal RPC_ERROR of type='server' and associated custom dialog class",
|
||||
async (assert) => {
|
||||
assert.expect(2);
|
||||
class CustomDialog extends LegacyComponent {}
|
||||
class CustomDialog extends Component {}
|
||||
CustomDialog.template = xml`<RPCErrorDialog title="'Strange Error'"/>`;
|
||||
CustomDialog.components = { RPCErrorDialog };
|
||||
class NormalDialog extends LegacyComponent {}
|
||||
class NormalDialog extends Component {}
|
||||
NormalDialog.template = xml`<RPCErrorDialog title="'Normal Error'"/>`;
|
||||
NormalDialog.components = { RPCErrorDialog };
|
||||
const error = new RPCError();
|
||||
|
||||
@@ -8,6 +8,8 @@ import { getFixture, mount } from "../helpers/utils";
|
||||
|
||||
const serviceRegistry = registry.category("services");
|
||||
|
||||
let target;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -23,10 +25,6 @@ async function createFileInput(config) {
|
||||
serviceRegistry.add("http", fakeHTTPService);
|
||||
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
if (config.onUploaded) {
|
||||
target.addEventListener("uploaded", config.onUploaded);
|
||||
}
|
||||
|
||||
const fileInput = await mount(FileInput, target, {
|
||||
env,
|
||||
@@ -39,7 +37,11 @@ async function createFileInput(config) {
|
||||
// Tests
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
QUnit.module("Components", () => {
|
||||
QUnit.module("Components", ({ beforeEach }) => {
|
||||
beforeEach(() => {
|
||||
target = getFixture();
|
||||
});
|
||||
|
||||
// This module cannot be tested as thoroughly as we want it to be:
|
||||
// browsers do not let scripts programmatically assign values to inputs
|
||||
// of type file
|
||||
@@ -48,7 +50,7 @@ QUnit.module("Components", () => {
|
||||
QUnit.test("Upload a file: default props", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const fileInput = await createFileInput({
|
||||
await createFileInput({
|
||||
mockPost: (route, params) => {
|
||||
assert.deepEqual(params, {
|
||||
csrf_token: odoo.csrf_token,
|
||||
@@ -59,10 +61,10 @@ QUnit.module("Components", () => {
|
||||
},
|
||||
props: {},
|
||||
});
|
||||
const input = fileInput.el.querySelector("input");
|
||||
const input = target.querySelector("input");
|
||||
|
||||
assert.strictEqual(
|
||||
fileInput.el.innerText.trim().toUpperCase(),
|
||||
target.querySelector(".o_file_input").innerText.trim().toUpperCase(),
|
||||
"CHOOSE FILE",
|
||||
"File input total text should match its given inner element's text"
|
||||
);
|
||||
@@ -77,13 +79,20 @@ QUnit.module("Components", () => {
|
||||
QUnit.test("Upload a file: custom attachment", async function (assert) {
|
||||
assert.expect(6);
|
||||
|
||||
const fileInput = await createFileInput({
|
||||
await createFileInput({
|
||||
props: {
|
||||
accepted_file_extensions: ".png",
|
||||
action: "/web/binary/upload_attachment",
|
||||
id: 5,
|
||||
model: "res.model",
|
||||
multi_upload: true,
|
||||
onUpload(files) {
|
||||
assert.strictEqual(
|
||||
files.length,
|
||||
0,
|
||||
"'files' property should be an empty array"
|
||||
);
|
||||
},
|
||||
},
|
||||
mockPost: (route, params) => {
|
||||
assert.deepEqual(params, {
|
||||
@@ -95,15 +104,8 @@ QUnit.module("Components", () => {
|
||||
assert.step(route);
|
||||
return "[]";
|
||||
},
|
||||
onUploaded(ev) {
|
||||
assert.strictEqual(
|
||||
ev.detail.files.length,
|
||||
0,
|
||||
"'files' property should be an empty array"
|
||||
);
|
||||
},
|
||||
});
|
||||
const input = fileInput.el.querySelector("input");
|
||||
const input = target.querySelector("input");
|
||||
|
||||
assert.strictEqual(input.accept, ".png", "Input should now only accept pngs");
|
||||
|
||||
|
||||
@@ -10,14 +10,13 @@ import { translatedTerms, _lt } from "@web/core/l10n/translation";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { patch, unpatch } from "@web/core/utils/patch";
|
||||
import { session } from "@web/session";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
const { DateTime, Settings } = luxon;
|
||||
|
||||
const terms = { Hello: "Bonjour" };
|
||||
const serviceRegistry = registry.category("services");
|
||||
class TestComponent extends LegacyComponent {}
|
||||
class TestComponent extends Component {}
|
||||
|
||||
/**
|
||||
* Patches the 'lang' of the user session and context.
|
||||
|
||||
@@ -17,9 +17,8 @@ import {
|
||||
patchWithCleanup,
|
||||
} from "../../helpers/utils";
|
||||
import { registerCleanup } from "../../helpers/cleanup";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
|
||||
let isXHRMocked = false;
|
||||
const serviceRegistry = registry.category("services");
|
||||
@@ -126,7 +125,7 @@ QUnit.test("rpc with simple routes", async (assert) => {
|
||||
});
|
||||
|
||||
QUnit.test("rpc coming from destroyed components are left pending", async (assert) => {
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.rpc = useService("rpc");
|
||||
}
|
||||
@@ -163,7 +162,7 @@ QUnit.test("rpc coming from destroyed components are left pending", async (asser
|
||||
|
||||
QUnit.test("rpc initiated from destroyed components throw exception", async (assert) => {
|
||||
assert.expect(1);
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.rpc = useService("rpc");
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import { popoverService } from "@web/core/popover/popover_service";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { clearRegistryWithCleanup, makeTestEnv } from "../../helpers/mock_env";
|
||||
import { click, getFixture, mount, nextTick } from "../../helpers/utils";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { Component, xml } = owl;
|
||||
|
||||
@@ -132,8 +131,8 @@ QUnit.test("close callback", async (assert) => {
|
||||
QUnit.test("sub component triggers close", async (assert) => {
|
||||
assert.containsOnce(fixture, ".o_popover_container");
|
||||
|
||||
class Comp extends LegacyComponent {}
|
||||
Comp.template = xml`<div id="comp" t-on-click="() => this.trigger('popover-closed')">in popover</div>`;
|
||||
class Comp extends Component {}
|
||||
Comp.template = xml`<div id="comp" t-on-click="() => this.props.close()">in popover</div>`;
|
||||
|
||||
popovers.add(popoverTarget, Comp, {});
|
||||
await nextTick();
|
||||
|
||||
@@ -15,7 +15,7 @@ QUnit.module("utils", () => {
|
||||
QUnit.module("useAutofocus");
|
||||
|
||||
QUnit.test("useAutofocus: simple usecase", async function (assert) {
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.inputRef = useAutofocus();
|
||||
}
|
||||
@@ -41,7 +41,7 @@ QUnit.module("utils", () => {
|
||||
});
|
||||
|
||||
QUnit.test("useAutofocus: conditional autofocus", async function (assert) {
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.inputRef = useAutofocus();
|
||||
this.showInput = true;
|
||||
@@ -113,7 +113,7 @@ QUnit.module("utils", () => {
|
||||
QUnit.module("useBus");
|
||||
|
||||
QUnit.test("useBus hook: simple usecase", async function (assert) {
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
useBus(this.env.bus, "test-event", this.myCallback);
|
||||
}
|
||||
@@ -144,13 +144,13 @@ QUnit.module("utils", () => {
|
||||
useListener("click", () => assert.step("click"));
|
||||
}
|
||||
}
|
||||
MyComponent.template = xml`<button>Click Me</button>`;
|
||||
MyComponent.template = xml`<button class="root">Click Me</button>`;
|
||||
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
const comp = await mount(MyComponent, target, { env });
|
||||
await mount(MyComponent, target, { env });
|
||||
|
||||
await click(comp.el);
|
||||
await click(target.querySelector(".root"));
|
||||
assert.verifySteps(["click"]);
|
||||
});
|
||||
|
||||
@@ -162,7 +162,7 @@ QUnit.module("utils", () => {
|
||||
}
|
||||
}
|
||||
MyComponent.template = xml`
|
||||
<div>
|
||||
<div class="root">
|
||||
<button t-if="flag">Click Here</button>
|
||||
<button t-else="">
|
||||
<span>or Here</span>
|
||||
@@ -173,15 +173,15 @@ QUnit.module("utils", () => {
|
||||
const target = getFixture();
|
||||
const comp = await mount(MyComponent, target, { env });
|
||||
|
||||
await click(comp.el);
|
||||
await click(target.querySelector(".root"));
|
||||
assert.verifySteps([]);
|
||||
await click(comp.el.querySelector("button"));
|
||||
await click(target.querySelector("button"));
|
||||
assert.verifySteps(["click"]);
|
||||
|
||||
comp.flag = false;
|
||||
comp.render();
|
||||
await nextTick();
|
||||
await click(comp.el.querySelector("button span"));
|
||||
await click(target.querySelector("button span"));
|
||||
assert.verifySteps(["click"]);
|
||||
});
|
||||
|
||||
@@ -193,7 +193,7 @@ QUnit.module("utils", () => {
|
||||
}
|
||||
}
|
||||
MyComponent.template = xml`
|
||||
<div>
|
||||
<div class="root">
|
||||
<button t-if="flag">Click Here</button>
|
||||
<button t-else="">
|
||||
<span>or Here</span>
|
||||
@@ -204,21 +204,21 @@ QUnit.module("utils", () => {
|
||||
const target = getFixture();
|
||||
const comp = await mount(MyComponent, target, { env });
|
||||
|
||||
await click(comp.el);
|
||||
await click(target.querySelector(".root"));
|
||||
assert.verifySteps([]);
|
||||
await click(comp.el.querySelector("button"));
|
||||
await click(target.querySelector("button"));
|
||||
assert.verifySteps(["click"]);
|
||||
|
||||
comp.flag = false;
|
||||
await comp.render();
|
||||
await click(comp.el.querySelector("button span"));
|
||||
await click(target.querySelector("button span"));
|
||||
assert.verifySteps(["click"]);
|
||||
});
|
||||
|
||||
QUnit.module("useService");
|
||||
|
||||
QUnit.test("useService: unavailable service", async function (assert) {
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
useService("toy_service");
|
||||
}
|
||||
@@ -235,7 +235,7 @@ QUnit.module("utils", () => {
|
||||
});
|
||||
|
||||
QUnit.test("useService: service that returns null", async function (assert) {
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
setup() {
|
||||
this.toyService = useService("toy_service");
|
||||
}
|
||||
|
||||
@@ -8,9 +8,8 @@ import testUtils from "web.test_utils";
|
||||
import { registerCleanup } from "../../helpers/cleanup";
|
||||
import { click, getFixture, legacyExtraNextTick, patchWithCleanup } from "../../helpers/utils";
|
||||
import { createWebClient, doAction, getActionManagerServerData } from "./../helpers";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
@@ -100,7 +99,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("can execute client actions from tag name", async function (assert) {
|
||||
assert.expect(4);
|
||||
class ClientAction extends LegacyComponent {}
|
||||
class ClientAction extends Component {}
|
||||
ClientAction.template = xml`<div class="o_client_action_test">Hello World</div>`;
|
||||
actionRegistry.add("HelloWorldTest", ClientAction);
|
||||
|
||||
@@ -232,7 +231,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("action can use a custom control panel (legacy)", async function (assert) {
|
||||
assert.expect(1);
|
||||
class CustomControlPanel extends LegacyComponent {}
|
||||
class CustomControlPanel extends Component {}
|
||||
CustomControlPanel.template = xml`
|
||||
<div class="custom-control-panel">My custom control panel</div>
|
||||
`;
|
||||
@@ -328,7 +327,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("ClientAction receives breadcrumbs and exports title (wowl)", async (assert) => {
|
||||
assert.expect(4);
|
||||
class ClientAction extends LegacyComponent {
|
||||
class ClientAction extends Component {
|
||||
setup() {
|
||||
this.breadcrumbTitle = "myOwlAction";
|
||||
const { breadcrumbs } = this.env.config;
|
||||
@@ -359,7 +358,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("ClientAction receives arbitrary props from doAction (wowl)", async (assert) => {
|
||||
assert.expect(1);
|
||||
class ClientAction extends LegacyComponent {
|
||||
class ClientAction extends Component {
|
||||
setup() {
|
||||
assert.strictEqual(this.props.division, "bell");
|
||||
}
|
||||
|
||||
@@ -13,9 +13,8 @@ import { legacyExtraNextTick, nextTick } from "../../helpers/utils";
|
||||
import { registry } from "@web/core/registry";
|
||||
import testUtils from "web.test_utils";
|
||||
import { useSetupView } from "@web/views/helpers/view_hook";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
const actionRegistry = registry.category("actions");
|
||||
|
||||
let serverData;
|
||||
@@ -444,7 +443,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
async function (assert) {
|
||||
assert.expect(3);
|
||||
const slowWillStartDef = testUtils.makeTestPromise();
|
||||
class ClientAction extends LegacyComponent {
|
||||
class ClientAction extends Component {
|
||||
setup() {
|
||||
owl.onWillStart(() => slowWillStartDef);
|
||||
}
|
||||
@@ -592,7 +591,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
let def = Promise.resolve();
|
||||
|
||||
let id = 1;
|
||||
class ToyView extends LegacyComponent {
|
||||
class ToyView extends Component {
|
||||
setup() {
|
||||
this.id = id++;
|
||||
assert.step(JSON.stringify(this.props.state || "no state"));
|
||||
|
||||
@@ -5,9 +5,8 @@ import { createWebClient, doAction, getActionManagerServerData } from "./../help
|
||||
import { registerCleanup } from "../../helpers/cleanup";
|
||||
import { click, getFixture, nextTick, patchWithCleanup } from "../../helpers/utils";
|
||||
import { errorService } from "@web/core/errors/error_service";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
@@ -23,7 +22,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("error in a client action (at rendering)", async function (assert) {
|
||||
assert.expect(4);
|
||||
class Boom extends LegacyComponent {}
|
||||
class Boom extends Component {}
|
||||
Boom.template = xml`<div><t t-esc="a.b.c"/></div>`;
|
||||
actionRegistry.add("Boom", Boom);
|
||||
|
||||
@@ -54,7 +53,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
registry.category("services").add("error", errorService);
|
||||
|
||||
class Boom extends LegacyComponent {
|
||||
class Boom extends Component {
|
||||
setup() {
|
||||
this.boom = false;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,8 @@ import {
|
||||
setupWebClientRegistries,
|
||||
} from "./../helpers";
|
||||
import { errorService } from "@web/core/errors/error_service";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
@@ -182,7 +181,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("properly load client actions", async function (assert) {
|
||||
assert.expect(3);
|
||||
class ClientAction extends LegacyComponent {}
|
||||
class ClientAction extends Component {}
|
||||
ClientAction.template = xml`<div class="o_client_action_test">Hello World</div>`;
|
||||
actionRegistry.add("HelloWorldTest", ClientAction);
|
||||
const mockRPC = async function (route, args) {
|
||||
@@ -1014,7 +1013,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
QUnit.test("concurrent hashchange during action mounting -- 1", async (assert) => {
|
||||
assert.expect(5);
|
||||
|
||||
class MyAction extends LegacyComponent {
|
||||
class MyAction extends Component {
|
||||
setup() {
|
||||
owl.onMounted(() => {
|
||||
assert.step("myAction mounted");
|
||||
@@ -1045,7 +1044,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
const baseURL = new URL(browser.location.href).toString();
|
||||
|
||||
class MyAction extends LegacyComponent {
|
||||
class MyAction extends Component {
|
||||
setup() {
|
||||
owl.onMounted(() => {
|
||||
assert.step("myAction mounted");
|
||||
|
||||
@@ -12,9 +12,8 @@ import {
|
||||
patchWithCleanup,
|
||||
} from "../../helpers/utils";
|
||||
import { createWebClient, doAction, getActionManagerServerData } from "./../helpers";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
@@ -77,7 +76,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("actions can push state", async (assert) => {
|
||||
assert.expect(5);
|
||||
class ClientActionPushes extends LegacyComponent {
|
||||
class ClientActionPushes extends Component {
|
||||
setup() {
|
||||
this.router = useService("router");
|
||||
}
|
||||
@@ -105,7 +104,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("actions override previous state", async (assert) => {
|
||||
assert.expect(5);
|
||||
class ClientActionPushes extends LegacyComponent {
|
||||
class ClientActionPushes extends Component {
|
||||
setup() {
|
||||
this.router = useService("router");
|
||||
}
|
||||
@@ -134,7 +133,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
|
||||
QUnit.test("actions override previous state from menu click", async (assert) => {
|
||||
assert.expect(3);
|
||||
class ClientActionPushes extends LegacyComponent {
|
||||
class ClientActionPushes extends Component {
|
||||
setup() {
|
||||
this.router = useService("router");
|
||||
}
|
||||
|
||||
@@ -17,9 +17,8 @@ import { registerCleanup } from "../../helpers/cleanup";
|
||||
import { errorService } from "@web/core/errors/error_service";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
import { ClientErrorDialog } from "@web/core/errors/error_dialogs";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { onMounted, xml } = owl;
|
||||
const { Component, onMounted, xml } = owl;
|
||||
|
||||
let serverData;
|
||||
let target;
|
||||
@@ -339,7 +338,7 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
onUnhandledRejection: () => {},
|
||||
});
|
||||
|
||||
class ErrorClientAction extends LegacyComponent {
|
||||
class ErrorClientAction extends Component {
|
||||
setup() {
|
||||
throw new Error("my error");
|
||||
}
|
||||
@@ -347,11 +346,11 @@ QUnit.module("ActionManager", (hooks) => {
|
||||
ErrorClientAction.template = xml`<div/>`;
|
||||
registry.category("actions").add("failing", ErrorClientAction);
|
||||
|
||||
class ClientActionTargetNew extends LegacyComponent {}
|
||||
class ClientActionTargetNew extends Component {}
|
||||
ClientActionTargetNew.template = xml`<div class="my_action_new" />`;
|
||||
registry.category("actions").add("clientActionNew", ClientActionTargetNew);
|
||||
|
||||
class ClientAction extends LegacyComponent {
|
||||
class ClientAction extends Component {
|
||||
setup() {
|
||||
this.action = useService("action");
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ import { ClientActionAdapter, ViewAdapter } from "@web/legacy/action_adapters";
|
||||
import { commandService } from "@web/core/commands/command_service";
|
||||
import { CustomFavoriteItem } from "@web/search/favorite_menu/custom_favorite_item";
|
||||
import { standaloneAdapter } from "web.OwlCompatibility";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { Component, onMounted, xml } = owl;
|
||||
|
||||
@@ -317,7 +316,7 @@ export async function loadState(env, state) {
|
||||
|
||||
export function getActionManagerServerData() {
|
||||
// additional basic client action
|
||||
class TestClientAction extends LegacyComponent {}
|
||||
class TestClientAction extends Component {}
|
||||
TestClientAction.template = xml`
|
||||
<div class="test_client_action">
|
||||
ClientAction_<t t-esc="props.action.params?.description"/>
|
||||
|
||||
@@ -17,6 +17,7 @@ import { uiService } from "@web/core/ui/ui_service";
|
||||
import { session } from "@web/session";
|
||||
|
||||
const serviceRegistry = registry.category("services");
|
||||
let target;
|
||||
|
||||
async function createSwitchCompanyMenu(routerParams = {}, toggleDelay = 0) {
|
||||
patchWithCleanup(MobileSwitchCompanyMenu, { toggleDelay });
|
||||
@@ -34,13 +35,13 @@ async function createSwitchCompanyMenu(routerParams = {}, toggleDelay = 0) {
|
||||
});
|
||||
}
|
||||
const env = await makeTestEnv();
|
||||
const target = getFixture();
|
||||
const scMenu = await mount(MobileSwitchCompanyMenu, target, { env });
|
||||
return scMenu;
|
||||
}
|
||||
|
||||
QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
QUnit.module("MobileSwitchCompanyMenu", (hooks) => {
|
||||
hooks.beforeEach(() => {
|
||||
target = getFixture();
|
||||
patchWithCleanup(session.user_companies, {
|
||||
allowed_companies: {
|
||||
1: { id: 1, name: "Hermit" },
|
||||
@@ -57,34 +58,34 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
QUnit.test("basic rendering", async (assert) => {
|
||||
assert.expect(13);
|
||||
|
||||
const scMenu = await createSwitchCompanyMenu();
|
||||
await createSwitchCompanyMenu();
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
assert.strictEqual(scMenu.el.tagName.toUpperCase(), "DIV");
|
||||
assert.hasClass(scMenu.el, "o_burger_menu_companies");
|
||||
|
||||
assert.containsN(scMenu, ".toggle_company", 3);
|
||||
assert.containsN(scMenu, ".log_into", 3);
|
||||
assert.containsOnce(scMenu.el, ".fa-check-square");
|
||||
assert.containsN(scMenu.el, ".fa-square-o", 2);
|
||||
assert.strictEqual(scMenuEl.tagName.toUpperCase(), "DIV");
|
||||
assert.hasClass(scMenuEl, "o_burger_menu_companies");
|
||||
assert.containsN(scMenuEl, ".toggle_company", 3);
|
||||
assert.containsN(scMenuEl, ".log_into", 3);
|
||||
assert.containsOnce(scMenuEl, ".fa-check-square");
|
||||
assert.containsN(scMenuEl, ".fa-square-o", 2);
|
||||
|
||||
assert.strictEqual(
|
||||
scMenu.el.querySelectorAll(".menu_companies_item")[0].textContent,
|
||||
scMenuEl.querySelectorAll(".menu_companies_item")[0].textContent,
|
||||
"Hermit(current)"
|
||||
);
|
||||
assert.strictEqual(
|
||||
scMenu.el.querySelectorAll(".menu_companies_item")[1].textContent,
|
||||
scMenuEl.querySelectorAll(".menu_companies_item")[1].textContent,
|
||||
"Herman's"
|
||||
);
|
||||
assert.strictEqual(
|
||||
scMenu.el.querySelectorAll(".menu_companies_item")[2].textContent,
|
||||
scMenuEl.querySelectorAll(".menu_companies_item")[2].textContent,
|
||||
"Heroes TM"
|
||||
);
|
||||
|
||||
assert.hasClass(scMenu.el.querySelectorAll(".menu_companies_item i")[0], "fa-check-square");
|
||||
assert.hasClass(scMenu.el.querySelectorAll(".menu_companies_item i")[1], "fa-square-o");
|
||||
assert.hasClass(scMenu.el.querySelectorAll(".menu_companies_item i")[2], "fa-square-o");
|
||||
assert.hasClass(scMenuEl.querySelectorAll(".menu_companies_item i")[0], "fa-check-square");
|
||||
assert.hasClass(scMenuEl.querySelectorAll(".menu_companies_item i")[1], "fa-square-o");
|
||||
assert.hasClass(scMenuEl.querySelectorAll(".menu_companies_item i")[2], "fa-square-o");
|
||||
|
||||
assert.strictEqual(scMenu.el.textContent, "CompaniesHermit(current)Herman'sHeroes TM");
|
||||
assert.strictEqual(scMenuEl.textContent, "CompaniesHermit(current)Herman'sHeroes TM");
|
||||
});
|
||||
|
||||
QUnit.test("companies can be toggled: toggle a second company", async (assert) => {
|
||||
@@ -96,6 +97,7 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
prom.resolve();
|
||||
}
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
/**
|
||||
* [x] **Company 1**
|
||||
@@ -104,18 +106,18 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
*/
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [1]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id]", 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id]", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 2);
|
||||
|
||||
/**
|
||||
* [x] **Company 1**
|
||||
* [x] Company 2 -> toggle
|
||||
* [ ] Company 3
|
||||
*/
|
||||
await click(scMenu.el.querySelectorAll(".toggle_company")[1]);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 1);
|
||||
await click(scMenuEl.querySelectorAll(".toggle_company")[1]);
|
||||
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"]);
|
||||
});
|
||||
@@ -129,6 +131,7 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
prom.resolve();
|
||||
}
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState }, 50);
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
/**
|
||||
* [x] **Company 1**
|
||||
@@ -137,20 +140,20 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
*/
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [1]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id]", 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id]", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 2);
|
||||
|
||||
/**
|
||||
* [ ] **Company 1** -> toggle all
|
||||
* [x] Company 2 -> toggle all
|
||||
* [x] Company 3 -> toggle all
|
||||
*/
|
||||
await click(scMenu.el.querySelectorAll(".toggle_company")[0]);
|
||||
await click(scMenu.el.querySelectorAll(".toggle_company")[1]);
|
||||
await click(scMenu.el.querySelectorAll(".toggle_company")[2]);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 1);
|
||||
await click(scMenuEl.querySelectorAll(".toggle_company")[0]);
|
||||
await click(scMenuEl.querySelectorAll(".toggle_company")[1]);
|
||||
await click(scMenuEl.querySelectorAll(".toggle_company")[2]);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 1);
|
||||
|
||||
assert.verifySteps([]);
|
||||
await prom; // await toggle promise
|
||||
@@ -166,6 +169,7 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
},
|
||||
});
|
||||
const scMenu = await createSwitchCompanyMenu();
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
/**
|
||||
* [x] **Company 1**
|
||||
@@ -175,21 +179,21 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
assert.deepEqual(scMenu.env.services.router.current.hash, { cids: 1 });
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [1]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id]", 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id]", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 2);
|
||||
|
||||
/**
|
||||
* [ ] **Company 1** -> toggle off
|
||||
* [ ] Company 2
|
||||
* [ ] Company 3
|
||||
*/
|
||||
await click(scMenu.el.querySelectorAll(".toggle_company")[0]);
|
||||
await click(scMenuEl.querySelectorAll(".toggle_company")[0]);
|
||||
assert.deepEqual(scMenu.env.services.router.current.hash, { cids: 1 });
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [1]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-squarqe", 0);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-squarqe", 0);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 3);
|
||||
});
|
||||
|
||||
QUnit.test("single company mode: companies can be logged in", async (assert) => {
|
||||
@@ -199,6 +203,7 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
assert.step(url.split("#")[1]);
|
||||
}
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
/**
|
||||
* [x] **Company 1**
|
||||
@@ -207,16 +212,16 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
*/
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [1]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id]", 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id]", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 2);
|
||||
|
||||
/**
|
||||
* [x] **Company 1**
|
||||
* [ ] Company 2 -> log into
|
||||
* [ ] Company 3
|
||||
*/
|
||||
await click(scMenu.el.querySelectorAll(".log_into")[1]);
|
||||
await click(scMenuEl.querySelectorAll(".log_into")[1]);
|
||||
assert.verifySteps(["cids=2"]);
|
||||
});
|
||||
|
||||
@@ -228,6 +233,7 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
}
|
||||
Object.assign(browser.location, { hash: "cids=3%2C1" });
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
/**
|
||||
* [x] Company 1
|
||||
@@ -236,16 +242,16 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
*/
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [3, 1]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id]", 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 1);
|
||||
assert.containsN(scMenuEl, "[data-company-id]", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 1);
|
||||
|
||||
/**
|
||||
* [x] Company 1
|
||||
* [ ] Company 2 -> log into
|
||||
* [x] **Company 3**
|
||||
*/
|
||||
await click(scMenu.el.querySelectorAll(".log_into")[1]);
|
||||
await click(scMenuEl.querySelectorAll(".log_into")[1]);
|
||||
assert.verifySteps(["cids=2%2C3%2C1"]);
|
||||
});
|
||||
|
||||
@@ -257,6 +263,7 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
}
|
||||
Object.assign(browser.location, { hash: "cids=2%2C3" });
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState });
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
/**
|
||||
* [ ] Company 1
|
||||
@@ -265,16 +272,16 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
*/
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [2, 3]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 2);
|
||||
assert.containsN(scMenu.el, "[data-company-id]", 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 1);
|
||||
assert.containsN(scMenuEl, "[data-company-id]", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 1);
|
||||
|
||||
/**
|
||||
* [ ] Company 1
|
||||
* [x] **Company 2**
|
||||
* [x] Company 3 -> log into
|
||||
*/
|
||||
await click(scMenu.el.querySelectorAll(".log_into")[2]);
|
||||
await click(scMenuEl.querySelectorAll(".log_into")[2]);
|
||||
assert.verifySteps(["cids=3%2C2"]);
|
||||
});
|
||||
|
||||
@@ -285,6 +292,7 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
assert.step(url.split("#")[1]);
|
||||
}
|
||||
const scMenu = await createSwitchCompanyMenu({ onPushState }, 50);
|
||||
const scMenuEl = target.querySelector(".o_burger_menu_companies");
|
||||
|
||||
/**
|
||||
* [x] **Company 1**
|
||||
@@ -293,18 +301,18 @@ QUnit.module("MobileMobileSwitchCompanyMenu", (hooks) => {
|
||||
*/
|
||||
assert.deepEqual(scMenu.env.services.company.allowedCompanyIds, [1]);
|
||||
assert.strictEqual(scMenu.env.services.company.currentCompany.id, 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id]", 3);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenu.el, "[data-company-id] .fa-square-o", 2);
|
||||
assert.containsN(scMenuEl, "[data-company-id]", 3);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-check-square", 1);
|
||||
assert.containsN(scMenuEl, "[data-company-id] .fa-square-o", 2);
|
||||
|
||||
/**
|
||||
* [ ] **Company 1** -> toggled
|
||||
* [ ] Company 2 -> logged in
|
||||
* [ ] Company 3 -> toggled
|
||||
*/
|
||||
await click(scMenu.el.querySelectorAll(".toggle_company")[2]);
|
||||
await click(scMenu.el.querySelectorAll(".toggle_company")[0]);
|
||||
await click(scMenu.el.querySelectorAll(".log_into")[1]);
|
||||
await click(scMenuEl.querySelectorAll(".toggle_company")[2]);
|
||||
await click(scMenuEl.querySelectorAll(".toggle_company")[0]);
|
||||
await click(scMenuEl.querySelectorAll(".log_into")[1]);
|
||||
assert.verifySteps(["cids=2"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,18 +18,19 @@ import {
|
||||
patchWithCleanup,
|
||||
makeDeferred,
|
||||
} from "../helpers/utils";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
const systrayRegistry = registry.category("systray");
|
||||
const serviceRegistry = registry.category("services");
|
||||
|
||||
class MySystrayItem extends LegacyComponent {}
|
||||
class MySystrayItem extends Component {}
|
||||
MySystrayItem.template = xml`<li class="my-item">my item</li>`;
|
||||
let baseConfig;
|
||||
let target;
|
||||
|
||||
QUnit.module("Navbar", {
|
||||
async beforeEach() {
|
||||
target = getFixture();
|
||||
serviceRegistry.add("menu", menuService);
|
||||
serviceRegistry.add("action", actionService);
|
||||
serviceRegistry.add("notification", notificationService);
|
||||
@@ -51,10 +52,9 @@ QUnit.module("Navbar", {
|
||||
|
||||
QUnit.test("can be rendered", async (assert) => {
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
const target = getFixture();
|
||||
const navbar = await mount(NavBar, target, { env });
|
||||
await mount(NavBar, target, { env });
|
||||
assert.containsOnce(
|
||||
navbar.el,
|
||||
target,
|
||||
".o_navbar_apps_menu button.dropdown-toggle",
|
||||
"1 apps menu toggler present"
|
||||
);
|
||||
@@ -62,9 +62,8 @@ QUnit.test("can be rendered", async (assert) => {
|
||||
|
||||
QUnit.test("dropdown menu can be toggled", async (assert) => {
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
const target = getFixture();
|
||||
const navbar = await mount(NavBar, target, { env });
|
||||
const dropdown = navbar.el.querySelector(".o_navbar_apps_menu");
|
||||
await mount(NavBar, target, { env });
|
||||
const dropdown = target.querySelector(".o_navbar_apps_menu");
|
||||
await click(dropdown, "button.dropdown-toggle");
|
||||
assert.containsOnce(dropdown, ".dropdown-menu");
|
||||
await click(dropdown, "button.dropdown-toggle");
|
||||
@@ -81,11 +80,10 @@ QUnit.test("data-menu-xmlid attribute on AppsMenu items", async (assert) => {
|
||||
5: { id: 5, children: [], name: "Sub menu", appID: 1, xmlid: "menu_5" },
|
||||
};
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
const target = getFixture();
|
||||
const navbar = await mount(NavBar, target, { env });
|
||||
await mount(NavBar, target, { env });
|
||||
|
||||
// check apps
|
||||
const appsMenu = navbar.el.querySelector(".o_navbar_apps_menu");
|
||||
const appsMenu = target.querySelector(".o_navbar_apps_menu");
|
||||
await click(appsMenu, "button.dropdown-toggle");
|
||||
const menuItems = appsMenu.querySelectorAll("a");
|
||||
assert.strictEqual(
|
||||
@@ -102,21 +100,20 @@ QUnit.test("data-menu-xmlid attribute on AppsMenu items", async (assert) => {
|
||||
// check menus
|
||||
env.services.menu.setCurrentMenu(1);
|
||||
await nextTick();
|
||||
assert.containsOnce(navbar, ".o_menu_sections .dropdown-item[data-menu-xmlid=menu_3]");
|
||||
assert.containsOnce(target, ".o_menu_sections .dropdown-item[data-menu-xmlid=menu_3]");
|
||||
|
||||
// check sub menus toggler
|
||||
assert.containsOnce(navbar, ".o_menu_sections button.dropdown-toggle[data-menu-xmlid=menu_4]");
|
||||
assert.containsOnce(target, ".o_menu_sections button.dropdown-toggle[data-menu-xmlid=menu_4]");
|
||||
|
||||
// check sub menus
|
||||
await click(navbar.el.querySelector(".o_menu_sections .dropdown-toggle"));
|
||||
assert.containsOnce(navbar, ".o_menu_sections .dropdown-item[data-menu-xmlid=menu_5]");
|
||||
await click(target.querySelector(".o_menu_sections .dropdown-toggle"));
|
||||
assert.containsOnce(target, ".o_menu_sections .dropdown-item[data-menu-xmlid=menu_5]");
|
||||
});
|
||||
|
||||
QUnit.test("navbar can display current active app", async (assert) => {
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
const target = getFixture();
|
||||
const navbar = await mount(NavBar, target, { env });
|
||||
const dropdown = navbar.el.querySelector(".o_navbar_apps_menu");
|
||||
await mount(NavBar, target, { env });
|
||||
const dropdown = target.querySelector(".o_navbar_apps_menu");
|
||||
// Open apps menu
|
||||
await click(dropdown, "button.dropdown-toggle");
|
||||
assert.containsOnce(
|
||||
@@ -137,19 +134,18 @@ QUnit.test("navbar can display current active app", async (assert) => {
|
||||
|
||||
QUnit.test("navbar can display systray items", async (assert) => {
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
const target = getFixture();
|
||||
const navbar = await mount(NavBar, target, { env });
|
||||
assert.containsOnce(navbar.el, "li.my-item");
|
||||
await mount(NavBar, target, { env });
|
||||
assert.containsOnce(target, "li.my-item");
|
||||
});
|
||||
|
||||
QUnit.test("navbar can display systray items ordered based on their sequence", async (assert) => {
|
||||
class MyItem1 extends LegacyComponent {}
|
||||
class MyItem1 extends Component {}
|
||||
MyItem1.template = xml`<li class="my-item-1">my item 1</li>`;
|
||||
class MyItem2 extends LegacyComponent {}
|
||||
class MyItem2 extends Component {}
|
||||
MyItem2.template = xml`<li class="my-item-2">my item 2</li>`;
|
||||
class MyItem3 extends LegacyComponent {}
|
||||
class MyItem3 extends Component {}
|
||||
MyItem3.template = xml`<li class="my-item-3">my item 3</li>`;
|
||||
class MyItem4 extends LegacyComponent {}
|
||||
class MyItem4 extends Component {}
|
||||
MyItem4.template = xml`<li class="my-item-4">my item 4</li>`;
|
||||
|
||||
clearRegistryWithCleanup(systrayRegistry);
|
||||
@@ -158,9 +154,8 @@ QUnit.test("navbar can display systray items ordered based on their sequence", a
|
||||
systrayRegistry.add("addon.myitem3", { Component: MyItem3 }, { sequence: 100 });
|
||||
systrayRegistry.add("addon.myitem4", { Component: MyItem4 });
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
const target = getFixture();
|
||||
const navbar = await mount(NavBar, target, { env });
|
||||
const menuSystray = navbar.el.getElementsByClassName("o_menu_systray")[0];
|
||||
await mount(NavBar, target, { env });
|
||||
const menuSystray = target.getElementsByClassName("o_menu_systray")[0];
|
||||
assert.containsN(menuSystray, "li", 4, "four systray items should be displayed");
|
||||
assert.strictEqual(menuSystray.innerText, "my item 3\nmy item 4\nmy item 2\nmy item 1");
|
||||
});
|
||||
@@ -188,51 +183,50 @@ QUnit.test("can adapt with 'more' menu sections behavior", async (assert) => {
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
|
||||
// Force the parent width, to make this test independent of screen size
|
||||
const target = getFixture();
|
||||
target.style.width = "1080px";
|
||||
|
||||
// Set menu and mount
|
||||
env.services.menu.setCurrentMenu(1);
|
||||
const navbar = await mount(MyNavbar, target, { env });
|
||||
await mount(MyNavbar, target, { env });
|
||||
assert.containsN(
|
||||
navbar.el,
|
||||
target,
|
||||
".o_menu_sections > *:not(.o_menu_sections_more):not(.d-none)",
|
||||
3,
|
||||
"should have 3 menu sections displayed (that are not the 'more' menu)"
|
||||
);
|
||||
assert.containsNone(navbar.el, ".o_menu_sections_more", "the 'more' menu should not exist");
|
||||
assert.containsNone(target, ".o_menu_sections_more", "the 'more' menu should not exist");
|
||||
// Force minimal width and dispatch window resize event
|
||||
navbar.el.style.width = "0%";
|
||||
target.style.width = "0%";
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
await nextTick();
|
||||
assert.containsOnce(
|
||||
navbar.el,
|
||||
target,
|
||||
".o_menu_sections > *:not(.d-none)",
|
||||
"only one menu section should be displayed"
|
||||
);
|
||||
assert.containsOnce(
|
||||
navbar.el,
|
||||
target,
|
||||
".o_menu_sections_more:not(.d-none)",
|
||||
"the displayed menu section should be the 'more' menu"
|
||||
);
|
||||
// Open the more menu
|
||||
await click(navbar.el, ".o_menu_sections_more .dropdown-toggle");
|
||||
await click(target, ".o_menu_sections_more .dropdown-toggle");
|
||||
assert.deepEqual(
|
||||
[...navbar.el.querySelectorAll(".dropdown-menu > *")].map((el) => el.textContent),
|
||||
[...target.querySelectorAll(".dropdown-menu > *")].map((el) => el.textContent),
|
||||
["Section 10", "Section 11", "Section 12", "Section 120", "Section 121", "Section 122"],
|
||||
"'more' menu should contain all hidden sections in correct order"
|
||||
);
|
||||
// Reset to full width and dispatch window resize event
|
||||
navbar.el.style.width = "100%";
|
||||
target.style.width = "100%";
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
await nextTick();
|
||||
assert.containsN(
|
||||
navbar.el,
|
||||
target,
|
||||
".o_menu_sections > *:not(.o_menu_sections_more):not(.d-none)",
|
||||
3,
|
||||
"should have 3 menu sections displayed (that are not the 'more' menu)"
|
||||
);
|
||||
assert.containsNone(navbar.el, ".o_menu_sections_more", "the 'more' menu should not exist");
|
||||
assert.containsNone(target, ".o_menu_sections_more", "the 'more' menu should not exist");
|
||||
// Check the navbar adaptation calls
|
||||
assert.verifySteps([
|
||||
"adapt -> hide 0/3 sections",
|
||||
@@ -272,13 +266,12 @@ QUnit.test(
|
||||
baseConfig.serverData.menus = newMenus;
|
||||
|
||||
// Force the parent width, to make this test independent of screen size
|
||||
const target = getFixture();
|
||||
target.style.width = "600px";
|
||||
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
const navbar = await mount(MyNavbar, target, { env });
|
||||
assert.strictEqual(navbar.currentAppSections.length, 0, "0 app sub menus");
|
||||
assert.strictEqual(navbar.el.offsetWidth, 600);
|
||||
assert.strictEqual(target.querySelector(".o_navbar").offsetWidth, 600);
|
||||
assert.strictEqual(adaptCount, 1);
|
||||
assert.strictEqual(
|
||||
adaptRenderCount,
|
||||
@@ -287,10 +280,10 @@ QUnit.test(
|
||||
);
|
||||
|
||||
// Force minimal width and dispatch window resize event
|
||||
navbar.el.style.width = "0%";
|
||||
target.querySelector(".o_navbar").style.width = "0%";
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
await nextTick();
|
||||
assert.strictEqual(navbar.el.offsetWidth, 0);
|
||||
assert.strictEqual(target.querySelector(".o_navbar").offsetWidth, 0);
|
||||
assert.strictEqual(adaptCount, 2);
|
||||
assert.strictEqual(
|
||||
adaptRenderCount,
|
||||
@@ -315,7 +308,7 @@ QUnit.test(
|
||||
);
|
||||
|
||||
// Force 40% width and dispatch window resize event
|
||||
navbar.el.style.width = "40%";
|
||||
target.querySelector(".o_navbar").style.width = "40%";
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
await nextTick();
|
||||
assert.strictEqual(
|
||||
@@ -331,7 +324,7 @@ QUnit.test(
|
||||
);
|
||||
|
||||
// Reset to full width and dispatch window resize event
|
||||
navbar.el.style.width = "100%";
|
||||
target.querySelector(".o_navbar").style.width = "100%";
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
await nextTick();
|
||||
assert.strictEqual(navbar.currentAppSections.length, 3, "still 3 app sub menus");
|
||||
@@ -373,46 +366,45 @@ QUnit.test("'more' menu sections properly updated on app change", async (assert)
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
|
||||
// Force the parent width, to make this test independent of screen size
|
||||
const target = getFixture();
|
||||
target.style.width = "1080px";
|
||||
|
||||
// Set App1 menu and mount
|
||||
env.services.menu.setCurrentMenu(1);
|
||||
const navbar = await mount(NavBar, target, { env });
|
||||
await mount(NavBar, target, { env });
|
||||
|
||||
// Force minimal width and dispatch window resize event
|
||||
navbar.el.style.width = "0%";
|
||||
target.style.width = "0%";
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
await nextTick();
|
||||
assert.containsOnce(
|
||||
navbar.el,
|
||||
target,
|
||||
".o_menu_sections > *:not(.d-none)",
|
||||
"only one menu section should be displayed"
|
||||
);
|
||||
assert.containsOnce(
|
||||
navbar.el,
|
||||
target,
|
||||
".o_menu_sections_more:not(.d-none)",
|
||||
"the displayed menu section should be the 'more' menu"
|
||||
);
|
||||
|
||||
// Open the more menu
|
||||
await click(navbar.el, ".o_menu_sections_more .dropdown-toggle");
|
||||
await click(target, ".o_menu_sections_more .dropdown-toggle");
|
||||
assert.deepEqual(
|
||||
[...navbar.el.querySelectorAll(".dropdown-menu > *")].map((el) => el.textContent),
|
||||
[...target.querySelectorAll(".dropdown-menu > *")].map((el) => el.textContent),
|
||||
["Section 10", "Section 11", "Section 12", "Section 120", "Section 121", "Section 122"],
|
||||
"'more' menu should contain App1 sections"
|
||||
);
|
||||
// Close the more menu
|
||||
await click(navbar.el, ".o_menu_sections_more .dropdown-toggle");
|
||||
await click(target, ".o_menu_sections_more .dropdown-toggle");
|
||||
|
||||
// Set App2 menu
|
||||
env.services.menu.setCurrentMenu(2);
|
||||
await nextTick();
|
||||
|
||||
// Open the more menu
|
||||
await click(navbar.el, ".o_menu_sections_more .dropdown-toggle");
|
||||
await click(target, ".o_menu_sections_more .dropdown-toggle");
|
||||
assert.deepEqual(
|
||||
[...navbar.el.querySelectorAll(".dropdown-menu > *")].map((el) => el.textContent),
|
||||
[...target.querySelectorAll(".dropdown-menu > *")].map((el) => el.textContent),
|
||||
["Section 20", "Section 21", "Section 22", "Section 220", "Section 221", "Section 222"],
|
||||
"'more' menu should contain App2 sections"
|
||||
);
|
||||
@@ -438,8 +430,6 @@ QUnit.test("Do not execute adapt when navbar is destroyed", async (assert) => {
|
||||
}
|
||||
const env = await makeTestEnv(baseConfig);
|
||||
|
||||
const target = getFixture();
|
||||
|
||||
// Set menu and mount
|
||||
env.services.menu.setCurrentMenu(1);
|
||||
const navbar = await mount(MyNavbar, target, { env });
|
||||
|
||||
@@ -13,9 +13,8 @@ import { WebClient } from "@web/webclient/webclient";
|
||||
import { clearRegistryWithCleanup, makeTestEnv } from "../helpers/mock_env";
|
||||
import { fakeTitleService } from "../helpers/mock_services";
|
||||
import { destroy, getFixture, mount, patchWithCleanup, triggerEvent } from "../helpers/utils";
|
||||
import { LegacyComponent } from "@web/legacy/legacy_component";
|
||||
|
||||
const { xml } = owl;
|
||||
const { Component, xml } = owl;
|
||||
const mainComponentRegistry = registry.category("main_components");
|
||||
const serviceRegistry = registry.category("services");
|
||||
|
||||
@@ -48,7 +47,7 @@ QUnit.test("can be rendered", async (assert) => {
|
||||
|
||||
QUnit.test("can render a main component", async (assert) => {
|
||||
assert.expect(1);
|
||||
class MyComponent extends LegacyComponent {}
|
||||
class MyComponent extends Component {}
|
||||
MyComponent.template = xml`<span class="chocolate">MyComponent</span>`;
|
||||
clearRegistryWithCleanup(mainComponentRegistry);
|
||||
mainComponentRegistry.add("mycomponent", { Component: MyComponent });
|
||||
@@ -75,7 +74,7 @@ QUnit.test("control-click propagation stopped on <a href/>", async (assert) => {
|
||||
},
|
||||
});
|
||||
|
||||
class MyComponent extends LegacyComponent {
|
||||
class MyComponent extends Component {
|
||||
/** @param {MouseEvent} ev */
|
||||
onclick(ev) {
|
||||
assert.step(ev.ctrlKey ? "ctrl-click" : "click");
|
||||
@@ -89,8 +88,8 @@ QUnit.test("control-click propagation stopped on <a href/>", async (assert) => {
|
||||
// Mount the component as standalone and control-click the <a href/>
|
||||
const standaloneComponent = await mount(MyComponent, target, { env });
|
||||
assert.verifySteps([]);
|
||||
await triggerEvent(standaloneComponent.el, "", "click", { ctrlKey: false });
|
||||
await triggerEvent(standaloneComponent.el, "", "click", { ctrlKey: true });
|
||||
await triggerEvent(target.querySelector(".MyComponent"), "", "click", { ctrlKey: false });
|
||||
await triggerEvent(target.querySelector(".MyComponent"), "", "click", { ctrlKey: true });
|
||||
assert.verifySteps(["click", "ctrl-click"]);
|
||||
destroy(standaloneComponent);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user