Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions tools/devtools/rollup.config.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import terser from "rollup-plugin-terser";
import terser from "@rollup/plugin-terser";
import copy from "rollup-plugin-copy";
import execute from "rollup-plugin-execute";
import del from "rollup-plugin-delete";
Expand Down Expand Up @@ -50,7 +50,7 @@ export default ({ "config-browser": browser, "config-env": env }) => {
string({
include: "**/page_scripts/owl_devtools_global_hook.js",
}),
isProduction && terser.terser(),
isProduction && terser(),
],
};
}
Expand Down
51 changes: 25 additions & 26 deletions tools/devtools/src/devtools_app/context_menu/context_menu.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,35 @@
import { useStore } from "../store/store";
import { StorePlugin } from "../store/store";

const { Component, useEffect, useRef } = owl;
const { Component, useEffect, signal, plugin, props, types: t } = owl;

export class ContextMenu extends Component {
static template = "devtools.ContextMenu";
static props = {
items: Array,
};

props = props({ items: t.array() });

setup() {
this.store = useStore();
this.contextMenu = useRef("contextmenu");
useEffect(
(position) => {
const menu = this.contextMenu.el;
const menuWidth = menu.offsetWidth;
const menuHeight = menu.offsetHeight;
let { x, y } = position;
if (x + menuWidth > window.innerWidth) {
x = window.innerWidth - menuWidth;
}
if (y + menuHeight > window.innerHeight) {
y = window.innerHeight - menuHeight;
}
menu.style.left = x + "px";
// Need 25px offset because of the main navbar from the browser devtools
menu.style.top = y + "px";
},
() => [this.store.contextMenu?.position]
);
this.store = plugin(StorePlugin);
this.contextMenu = signal(null);
useEffect(() => {
const position = this.store.contextMenu()?.position;
const menu = this.contextMenu();
if (!menu || !position) return;
const menuWidth = menu.offsetWidth;
const menuHeight = menu.offsetHeight;
let { x, y } = position;
if (x + menuWidth > window.innerWidth) {
x = window.innerWidth - menuWidth;
}
if (y + menuHeight > window.innerHeight) {
y = window.innerHeight - menuHeight;
}
menu.style.left = x + "px";
// Need 25px offset because of the main navbar from the browser devtools
menu.style.top = y + "px";
});
}
onClickItem(action) {
action();
this.store.contextMenu = null;
this.store.contextMenu.set(null);
}
}
4 changes: 2 additions & 2 deletions tools/devtools/src/devtools_app/context_menu/context_menu.xml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<t t-name="devtools.ContextMenu">
<div class="custom-menu" t-ref="contextmenu">
<div class="custom-menu" t-ref="this.contextMenu">
<ul class="my-1">
<li t-foreach="props.items" t-as="item" t-key="item_index" t-if="item.show" t-esc="item.title" t-on-click.stop="() => this.onClickItem(item.action)" class="custom-menu-item py-1 px-4"/>
<li t-foreach="this.props.items" t-as="item" t-key="item_index" t-if="item.show" t-out="item.title" t-on-click.stop="() => this.onClickItem(item.action)" class="custom-menu-item py-1 px-4"/>
</ul>
</div>
</t>
Expand Down
3 changes: 2 additions & 1 deletion tools/devtools/src/devtools_app/devtools_panel.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/** @odoo-module **/

import { DevtoolsWindow } from "./devtools_window/devtools_window";
import { StorePlugin } from "./store/store";
const { mount } = owl;
import { templates } from "../../assets/templates.js";

for (const template in templates) {
owl.App.registerTemplate(template, templates[template]);
}
mount(DevtoolsWindow, document.body, { dev: true });
mount(DevtoolsWindow, document.body, { plugins: [StorePlugin] });
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { useStore } from "../../../store/store";
import { StorePlugin } from "../../../store/store";

const { Component } = owl;
const { Component, plugin } = owl;

export class ComponentSearchBar extends Component {
static template = "devtools.ComponentSearchBar";

setup() {
this.store = useStore();
this.store = plugin(StorePlugin);
}

updateSearch(event) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<t t-name="devtools.ComponentSearchBar" owl="1">
<t t-name="devtools.ComponentSearchBar">
<div class="mouse-icon p-1" t-on-click.stop='() => this.store.toggleSelector()'>
<i title="Select an element in the page to inspect the corresponding component" class="fa fa-fw fa-mouse-pointer" t-attf-style="color: {{store.componentSearch.activeSelector ? 'var(--active-icon)' : 'var(--text-color)'}};"></i>
<i title="Select an element in the page to inspect the corresponding component" class="fa fa-fw fa-mouse-pointer" t-attf-style="color: {{this.store.activeSelector() ? 'var(--active-icon)' : 'var(--text-color)'}};"></i>
</div>
<div class="icons-separator"/>
<div class="d-flex align-items-center ms-2 flex-grow-1">
<i class="fa fa-search search-icon" aria-hidden="true"></i>
<input type="text" class="search-input ms-1 w-100 border-0 h-100" placeholder="Search" t-on-keyup.stop="updateSearch" t-on-keydown.stop="onSearchKeyDown" t-att-value="store.componentSearch.search"/>
<t t-if="store.componentSearch.search.length > 0">
<t t-esc="store.componentSearch.searchResults.length ? store.componentSearch.searchIndex + 1 : 0"/>|<t t-esc="store.componentSearch.searchResults.length"/>
<i class="fa fa-angle-up lg-icon utility-icon ms-1 p-1" t-on-click.stop="() => this.store.componentSearch.getPrevSearch()"></i>
<i class="fa fa-angle-down lg-icon utility-icon p-1" t-on-click.stop="() => this.store.componentSearch.getNextSearch()"></i>
<input type="text" class="search-input ms-1 w-100 border-0 h-100" placeholder="Search" t-on-keyup.stop="this.updateSearch" t-on-keydown.stop="this.onSearchKeyDown" t-att-value="this.store.searchText()"/>
<t t-if="this.store.searchText().length > 0">
<t t-out="this.store.searchResults().length ? this.store.searchIndex() + 1 : 0"/>|<t t-out="this.store.searchResults().length"/>
<i class="fa fa-angle-up lg-icon utility-icon ms-1 p-1" t-on-click.stop="() => this.store.getPrevSearch()"></i>
<i class="fa fa-angle-down lg-icon utility-icon p-1" t-on-click.stop="() => this.store.getNextSearch()"></i>
<i class="fa fa-times lg-icon utility-icon p-1 me-2" t-on-click.stop='() => this.store.updateSearch("")'></i>
</t>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
/** @odoo-module **/

const { Component, onWillUnmount, useExternalListener } = owl;
const { Component, onWillDestroy, useListener, plugin } = owl;
import { TreeElement } from "./tree_element/tree_element";
import { DetailsWindow } from "./details_window/details_window";
import { ComponentSearchBar } from "./component_search_bar/component_search_bar";
import { useStore } from "../../store/store";
import { StorePlugin } from "../../store/store";

export class ComponentsTab extends Component {
static template = "devtools.ComponentsTab";

static components = { TreeElement, DetailsWindow, ComponentSearchBar };

setup() {
this.store = useStore();
this.store = plugin(StorePlugin);
this.flushRendersTimeout = false;
useExternalListener(document, "keydown", this.onKeyboardEvent);
useExternalListener(window, "resize", this.onWindowResize);
useListener(document, "keydown", this.onKeyboardEvent.bind(this));
useListener(window, "resize", this.onWindowResize);

onWillUnmount(() => {
onWillDestroy(() => {
window.removeEventListener("mousemove", this.onMouseMove);
window.removeEventListener("mouseup", this.onMouseUp);
});
Expand Down Expand Up @@ -56,9 +56,8 @@ export class ComponentsTab extends Component {
onMouseMove = (event) => {
const minWidth = (147 / window.innerWidth) * 100;
const maxWidth = 100 - (100 / window.innerWidth) * 100;
this.store.splitPosition = Math.max(
Math.min((event.clientX / window.innerWidth) * 100, maxWidth),
minWidth
this.store.splitPosition.set(
Math.max(Math.min((event.clientX / window.innerWidth) * 100, maxWidth), minWidth)
);
};

Expand All @@ -71,7 +70,7 @@ export class ComponentsTab extends Component {
onWindowResize = () => {
const minWidth = (147 / window.innerWidth) * 100;
if (minWidth <= 100) {
this.store.splitPosition = Math.max(this.store.splitPosition, minWidth);
this.store.splitPosition.set(Math.max(this.store.splitPosition(), minWidth));
}
};
}
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">
<t t-name="devtools.ComponentsTab" owl="1">
<t t-if="store.apps.length === 0">
<t t-name="devtools.ComponentsTab">
<t t-if="this.store.apps().length === 0">
<div class="status-message d-flex justify-content-center align-items-center">
There are no apps currently running.
</div>
</t>
<t t-else="">
<div class="position-relative overflow-hidden d-flex flex-row h-100">
<div class="split-screen-left d-flex flex-column" t-attf-style="width:{{store.splitPosition}}%;">
<div class="split-screen-left d-flex flex-column" t-attf-style="width:{{this.store.splitPosition()}}%;">
<div class="panel-top d-flex align-items-center">
<ComponentSearchBar/>
</div>
<div class="overflow-auto h-100 font-monospace">
<div id="tree-wrapper">
<t t-foreach="store.apps" t-as="app" t-key="app_index">
<TreeElement component="app"/>
<t t-foreach="this.store.apps()" t-as="app" t-key="app_index">
<TreeElement component="app"/>
</t>
</div>
</div>
</div>
<div
class="split-screen-border user-select-none"
t-on-mousedown="onMouseDown"
t-on-mousedown="this.onMouseDown"
/>
<div class="split-screen-right d-flex flex-column font-monospace" t-attf-style="width:{{100 - store.splitPosition}}%;">
<DetailsWindow t-if="store.activeComponent"/>
<div class="split-screen-right d-flex flex-column font-monospace" t-attf-style="width:{{100 - this.store.splitPosition()}}%;">
<DetailsWindow t-if="this.store.activeComponent()"/>
<t t-else="">
<div class="status-message d-flex justify-content-center align-items-center">
There was an error while processing this component.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,64 @@
const { Component } = owl;
import { useStore } from "../../../store/store";
const { Component, plugin } = owl;
import { StorePlugin } from "../../../store/store";
import { ObjectTreeElement } from "./object_tree_element/object_tree_element";

export class DetailsWindow extends Component {
static template = "devtools.DetailsWindow";
static components = { ObjectTreeElement };
setup() {
this.store = useStore();
this.store = plugin(StorePlugin);
}

get contextMenuItems() {
return [
{
title: "Inspect source code",
show: true,
action: () => this.store.inspectComponent("source", this.store.activeComponent.path),
action: () => this.store.inspectComponent("source", this.store.activeComponent().path),
},
{
title: "Store as global variable",
show: this.store.activeComponent.path.length !== 1,
show: this.store.activeComponent().path.length !== 1,
action: () =>
this.store.logObjectInConsole([
...this.store.activeComponent.path,
...this.store.activeComponent().path,
{ type: "item", value: "component" },
]),
},
{
title: "Inspect in Elements tab",
show: this.store.activeComponent.path.length !== 1,
action: () => this.store.inspectComponent("DOM", this.store.activeComponent.path),
show: this.store.activeComponent().path.length !== 1,
action: () => this.store.inspectComponent("DOM", this.store.activeComponent().path),
},
{
title: "Force rerender",
show: this.store.activeComponent.path.length !== 1,
action: () => this.store.refreshComponent(this.store.activeComponent.path),
show: this.store.activeComponent().path.length !== 1,
action: () => this.store.refreshComponent(this.store.activeComponent().path),
},
{
title: "Store observed states as global variable",
show: this.store.activeComponent.path.length !== 1,
show: this.store.activeComponent().path.length !== 1,
action: () =>
this.store.logObjectInConsole([
...this.store.activeComponent.path,
...this.store.activeComponent().path,
{ type: "item", value: "subscriptions" },
]),
},
{
title: "Inspect compiled template",
show: this.store.activeComponent.path.length !== 1,
show: this.store.activeComponent().path.length !== 1,
action: () =>
this.store.inspectComponent("compiled template", this.store.activeComponent.path),
this.store.inspectComponent("compiled template", this.store.activeComponent().path),
},
{
title: "Log raw template",
show: this.store.activeComponent.path.length !== 1,
action: () => this.store.inspectComponent("raw template", this.store.activeComponent.path),
show: this.store.activeComponent().path.length !== 1,
action: () => this.store.inspectComponent("raw template", this.store.activeComponent().path),
},
{
title: "Store as global variable",
show: this.store.activeComponent.path.length === 1,
action: () => this.store.logObjectInConsole([...this.store.activeComponent.path]),
show: this.store.activeComponent().path.length === 1,
action: () => this.store.logObjectInConsole([...this.store.activeComponent().path]),
},
];
}
Expand All @@ -68,6 +68,6 @@ export class DetailsWindow extends Component {
}

toggleCategory(ev, category) {
this.store.activeComponent[category].toggled = !this.store.activeComponent[category].toggled;
this.store.activeComponent()[category].toggled = !this.store.activeComponent()[category].toggled;
}
}
Loading
Loading