Skip to content
Merged
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
59 changes: 1 addition & 58 deletions addons/html_builder/static/src/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,13 @@ import {
useRef,
useState,
useSubEnv,
markup,
} from "@odoo/owl";
import { ConfirmationDialog } from "@web/core/confirmation_dialog/confirmation_dialog";
import { useHotkey } from "@web/core/hotkeys/hotkey_hook";
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { useService } from "@web/core/utils/hooks";
import { addLoadingEffect as addButtonLoadingEffect } from "@web/core/utils/ui";
import { RPCError } from "@web/core/network/rpc";
import { escape } from "@web/core/utils/strings";
import { user } from "@web/core/user";
import { useSetupAction } from "@web/search/action_hook";
import { AnchorPlugin } from "./core/plugins/anchor/anchor_plugin";
import { BuilderActionsPlugin } from "./core/plugins/builder_actions_plugin";
Expand All @@ -41,7 +37,6 @@ import { ReplacePlugin } from "./core/plugins/replace/replace_plugin";
import { SetupEditorPlugin } from "./core/plugins/setup_editor_plugin";
import { SnippetLifecyclePlugin } from "./core/plugins/snippet_lifecycle_plugin";
import { VisibilityPlugin } from "./core/plugins/visibility_plugin";
import { SnippetModel } from "./snippet_model";
import { InvisibleElementsPanel } from "./sidebar/invisible_elements_panel";
import { BlockTab } from "./sidebar/block_tab";
import { CustomizeTab } from "./sidebar/customize_tab";
Expand Down Expand Up @@ -153,19 +148,7 @@ export class Builder extends Component {
this.env.services
);

this.context = {
website_id: this.websiteService.currentWebsite.id,
lang: this.websiteService.currentWebsite.metadata.lang,
user_lang: user.context.lang,
};

this.snippetModel = useState(
new SnippetModel(this.env.services, {
snippetsName: this.props.snippetsName,
installSnippetModule: this.installSnippetModule.bind(this),
context: this.context,
})
);
this.snippetModel = useState(useService("html_builder.snippets"));

onWillStart(async () => {
await this.snippetModel.load();
Expand Down Expand Up @@ -343,46 +326,6 @@ export class Builder extends Component {
...this.editor.editable.querySelectorAll(this.getInvisibleSelector(isMobile)),
];
}

installSnippetModule(snippet) {
// TODO: Should be the app name, not the snippet name ... Maybe both ?
const bodyText = _t("Do you want to install %s App?", snippet.title);
const linkText = _t("More info about this app.");
const linkUrl =
"/odoo/action-base.open_module_tree/" + encodeURIComponent(snippet.moduleId);

this.dialog.add(ConfirmationDialog, {
title: _t("Install %s", snippet.title),
body: markup(
`${escape(bodyText)}\n<a href="${linkUrl}" target="_blank">${escape(linkText)}</a>`
),
confirm: async () => {
try {
await this.orm.call("ir.module.module", "button_immediate_install", [
[Number(snippet.moduleId)],
]);
// TODO Need to Reload webclient
// this._onSaveRequest({
// data: {
// reloadWebClient: true,
// },
// });
} catch (e) {
if (e instanceof RPCError) {
const message = escape(_t("Could not install module %s", snippet.title));
this.notification.add(message, {
type: "danger",
sticky: true,
});
return;
}
throw e;
}
},
confirmLabel: _t("Save and Install"),
cancel: () => {},
});
}
}

registry.category("lazy_components").add("website.Builder", Builder);
2 changes: 1 addition & 1 deletion addons/html_builder/static/src/builder.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
</div>
<div class="overflow-auto flex-grow-1 pt-1">
<t t-if="state.activeTab === 'blocks'">
<BlockTab snippetModel="snippetModel" installSnippetModule.bind="installSnippetModule"/>
<BlockTab />
</t>
<t t-if="state.activeTab === 'customize'">
<CustomizeTab currentOptionsContainers="state.currentOptionsContainers" snippetModel="snippetModel"/>
Expand Down
31 changes: 10 additions & 21 deletions addons/html_builder/static/src/sidebar/block_tab.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Component } from "@odoo/owl";
import { Component, useState } from "@odoo/owl";
import { useDraggable } from "@web/core/utils/draggable";
import { useService } from "@web/core/utils/hooks";
import { AddSnippetDialog } from "./add_snippet_dialog";
import { CustomInnerSnippet } from "./custom_inner_snippet";

// TODO move it in web (copy from web_studio)
Expand Down Expand Up @@ -34,14 +33,12 @@ function copyElementOnDrag() {
export class BlockTab extends Component {
static template = "html_builder.BlockTab";
static components = { CustomInnerSnippet };
static props = {
snippetModel: { type: Object },
installSnippetModule: { type: Function },
};
static props = {};

setup() {
this.dialog = useService("dialog");
this.orm = useService("orm");
this.snippetModel = useState(useService("html_builder.snippets"));

const copyOnDrag = copyElementOnDrag();
useDraggable({
Expand All @@ -55,7 +52,7 @@ export class BlockTab extends Component {
onDragStart: ({ element }) => {
copyOnDrag.insert();
const { category, id } = element.dataset;
const snippet = this.props.snippetModel.getSnippet(category, id);
const snippet = this.snippetModel.getSnippet(category, id);
this.dropzonePlugin.displayDropZone(snippet);
},
onDrag: ({ element }) => {
Expand All @@ -65,7 +62,7 @@ export class BlockTab extends Component {
const { x, y, height, width } = element.getClientRects()[0];
const position = { x, y, height, width };
const { category, id } = element.dataset;
const snippet = this.props.snippetModel.getSnippet(category, id);
const snippet = this.snippetModel.getSnippet(category, id);
if (category === "snippet_groups") {
this.openSnippetDialog(snippet, position);
return;
Expand Down Expand Up @@ -94,19 +91,11 @@ export class BlockTab extends Component {
if (addElement.noDrop) {
return;
}
this.dialog.add(
AddSnippetDialog,
{
selectedSnippet: snippet,
snippetModel: this.props.snippetModel,
selectSnippet: (snippet) => {
addElement(snippet.content.cloneNode(true));
},
installModule: this.props.installSnippetModule,
this.snippetModel.select(snippet, {
onSelect: (snippet) => {
addElement(snippet.content.cloneNode(true));
},
{
onClose: () => this.dropzonePlugin.clearDropZone(),
}
);
onClose: () => this.dropzonePlugin.clearDropZone(),
});
}
}
14 changes: 7 additions & 7 deletions addons/html_builder/static/src/sidebar/block_tab.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,33 @@
<div>Categories</div>
<div class="container">
<div class="row">
<div t-foreach="this.props.snippetModel.snippetGroups" t-as="snippet" t-key="snippet.id" class="col-4 p-1 o_draggable" t-att-data-category="'snippet_groups'" t-att-data-id="snippet.id">
<div t-foreach="this.snippetModel.snippetGroups" t-as="snippet" t-key="snippet.id" class="col-4 p-1 o_draggable" t-att-data-category="'snippet_groups'" t-att-data-id="snippet.id">
<div class="w-100 h-100 d-flex flex-column block" t-att-class="snippet.moduleId ? 'to_install' : '' " t-on-click="() => this.openSnippetDialog(snippet)">
<div class="img-container">
<img t-att-src="snippet.thumbnailSrc" class="w-100"/>
<button t-if="snippet.moduleId" class="btn btn-primary" t-on-click="() => this.props.installSnippetModule(snippet)">Install</button>
<button t-if="snippet.moduleId" class="btn btn-primary" t-on-click="() => this.snippetModel.installSnippetModule(snippet)">Install</button>
</div>
<span class="text-center" t-esc="snippet.title"/>
</div>
</div>
</div>
</div>

<t t-if="this.props.snippetModel.hasCustomInnerContents">
<t t-if="this.snippetModel.hasCustomInnerContents">
<div class="mt-1">Custom Inner Content</div>
<t t-foreach="this.props.snippetModel.snippetCustomInnerContents" t-as="snippet" t-key="snippet.id">
<CustomInnerSnippet snippet="snippet" snippetModel="this.props.snippetModel"/>
<t t-foreach="this.snippetModel.snippetCustomInnerContents" t-as="snippet" t-key="snippet.id">
<CustomInnerSnippet snippet="snippet" snippetModel="this.snippetModel"/>
</t>
</t>

<div class="mt-1">Inner Content</div>
<div class="container">
<div class="row">
<div t-foreach="this.props.snippetModel.snippetInnerContents" t-as="snippet" t-key="snippet.id" class="col-4 p-1 o_draggable" t-att-name="snippet.title" t-att-data-category="'snippet_content'" t-att-data-id="snippet.id">
<div t-foreach="this.snippetModel.snippetInnerContents" t-as="snippet" t-key="snippet.id" class="col-4 p-1 o_draggable" t-att-name="snippet.title" t-att-data-category="'snippet_content'" t-att-data-id="snippet.id">
<div class="w-100 h-100 d-flex flex-column block" t-att-class="snippet.moduleId ? 'to_install' : '' ">
<div class="img-container">
<img t-att-src="snippet.thumbnailSrc" class="w-100"/>
<button t-if="snippet.moduleId" class="btn btn-primary" t-on-click="() => this.props.installSnippetModule(snippet)">Install</button>
<button t-if="snippet.moduleId" class="btn btn-primary" t-on-click="() => this.snippetModel.installSnippetModule(snippet)">Install</button>
</div>
<span class="text-center" t-esc="snippet.title"/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export class AddSnippetDialog extends Component {
selectedSnippet: { type: Object },
selectSnippet: { type: Function },
snippetModel: { type: Object },
installModule: { type: Function },
close: { type: Function },
};

Expand All @@ -31,7 +30,6 @@ export class AddSnippetDialog extends Component {
this.props.close();
},
snippetModel: this.props.snippetModel,
installModule: this.props.installModule,
};

let root;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ import { _t } from "@web/core/l10n/translation";
import { uniqueId } from "@web/core/utils/functions";
import { Reactive } from "@web/core/utils/reactive";
import { escape } from "@web/core/utils/strings";
import { AddSnippetDialog } from "@html_builder/sidebar/add_snippet_dialog";
import { AddSnippetDialog } from "./add_snippet_dialog";
import { registry } from "@web/core/registry";
import { user } from "@web/core/user";
import { markup } from "@odoo/owl";
import { RPCError } from "@web/core/network/rpc";

export class SnippetModel extends Reactive {
constructor(services, { snippetsName, installSnippetModule, context }) {
constructor(services, { snippetsName, context }) {
super();
this.orm = services.orm;
this.dialog = services.dialog;
this.notification = services.notification;
this.snippetsName = snippetsName;
this.websiteService = services.website;
this.installSnippetModule = installSnippetModule;
this.context = context;

this.snippetsByCategory = {
Expand Down Expand Up @@ -71,6 +75,58 @@ export class SnippetModel extends Reactive {
return this.snippetsByCategory[category].filter((snippet) => snippet.id === id)[0];
}

installSnippetModule(snippet) {
// TODO: Should be the app name, not the snippet name ... Maybe both ?
const bodyText = _t("Do you want to install %s App?", snippet.title);
const linkText = _t("More info about this app.");
const linkUrl =
"/odoo/action-base.open_module_tree/" + encodeURIComponent(snippet.moduleId);

this.dialog.add(ConfirmationDialog, {
title: _t("Install %s", snippet.title),
body: markup(
`${escape(bodyText)}\n<a href="${linkUrl}" target="_blank">${escape(linkText)}</a>`
),
confirm: async () => {
try {
await this.orm.call("ir.module.module", "button_immediate_install", [
[Number(snippet.moduleId)],
]);
// TODO Need to Reload webclient
// this._onSaveRequest({
// data: {
// reloadWebClient: true,
// },
// });
} catch (e) {
if (e instanceof RPCError) {
const message = escape(_t("Could not install module %s", snippet.title));
this.notification.add(message, {
type: "danger",
sticky: true,
});
return;
}
throw e;
}
},
confirmLabel: _t("Save and Install"),
cancel: () => {},
});
}

select(snippet, { onSelect, onClose }) {
this.dialog.add(
AddSnippetDialog,
{
selectedSnippet: snippet,
snippetModel: this,
selectSnippet: onSelect,
},
{ onClose }
);
}

async load() {
const context = { ...this.context, rendering_bundle: true };
if (context.user_lang) {
Expand Down Expand Up @@ -242,7 +298,6 @@ export class SnippetModel extends Reactive {
newSnippet = selectedSnippet.content.cloneNode(true);
snippetToReplace.replaceWith(newSnippet);
},
installModule: this.installSnippetModule,
},
{ onClose: () => resolve() }
);
Expand Down Expand Up @@ -314,3 +369,21 @@ export class SnippetModel extends Reactive {
});
}
}

registry.category("services").add("html_builder.snippets", {
dependencies: ["orm", "dialog", "website", "notification"],

start(env, { orm, dialog, website, notification }) {
const services = { orm, dialog, website, notification };
const context = {
website_id: website.currentWebsite?.id,
lang: website.currentWebsite?.metadata.lang,
user_lang: user.context.lang,
};

return new SnippetModel(services, {
snippetsName: "website.snippets",
context,
});
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export class SnippetViewer extends Component {
state: { type: Object },
selectSnippet: { type: Function },
snippetModel: { type: Object },
installModule: { type: Function },
};

setup() {
Expand Down Expand Up @@ -50,7 +49,7 @@ export class SnippetViewer extends Component {

onClick(snippet) {
if (snippet.moduleId) {
this.props.installModule(snippet);
this.props.snippetModel.installModule(snippet);
} else {
this.props.selectSnippet(snippet);
}
Expand Down
2 changes: 1 addition & 1 deletion addons/html_builder/static/tests/options/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { setupWebsiteBuilder } from "../helpers";
import { SnippetModel } from "@html_builder/snippet_model";
import { SnippetModel } from "@html_builder/snippets/snippet_service";
import { getMockEnv, makeMockEnv, mockService } from "@web/../tests/web_test_helpers";

export async function getStructureSnippet(snippetName) {
Expand Down