Eliminate Python dependency: embed frontend assets in odoo-go

- Copy all OWL frontend assets (JS/CSS/XML/fonts/images) into frontend/
  directory (2925 files, 43MB) — no more runtime reads from Python Odoo
- Replace OdooAddonsPath config with FrontendDir pointing to local frontend/
- Rewire bundle.go, static.go, templates.go, webclient.go to read from
  frontend/ instead of external Python Odoo addons directory
- Auto-detect frontend/ and build/ dirs relative to binary in main.go
- Delete obsolete Python helper scripts (tools/*.py)

The Go server is now fully self-contained: single binary + frontend/ folder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marc
2026-03-31 23:09:12 +02:00
parent 0ed29fe2fd
commit 8741282322
2933 changed files with 280644 additions and 264 deletions

View File

@@ -0,0 +1,31 @@
import {
many2OneAvatarUserField,
Many2OneAvatarUserField,
} from "@mail/views/web/fields/many2one_avatar_user_field/many2one_avatar_user_field";
import { registry } from "@web/core/registry";
export class Many2OneAvatarLeaderUserField extends Many2OneAvatarUserField {
static props = {
...Many2OneAvatarUserField.props,
teamField: String,
};
get m2oProps() {
return {
...super.m2oProps,
context: {
...super.m2oProps.context,
crm_formatted_display_name_team: Number(this.props.record.data[this.props.teamField].id),
},
};
}
}
registry.category("fields").add("many2one_avatar_leader_user", {
...many2OneAvatarUserField,
component: Many2OneAvatarLeaderUserField,
extractProps: (fieldInfo, dynamicInfo) => ({
...many2OneAvatarUserField.extractProps(fieldInfo, dynamicInfo),
teamField: fieldInfo.attrs.teamField,
}),
});

View File

@@ -0,0 +1,101 @@
import { _t } from "@web/core/l10n/translation";
import { registry } from "@web/core/registry";
import { stepUtils } from "@web_tour/tour_utils";
import { markup } from "@odoo/owl";
registry.category("web_tour.tours").add('crm_tour', {
url: "/odoo",
steps: () => [stepUtils.showAppsMenuItem(), {
isActive: ["community"],
trigger: '.o_app[data-menu-xmlid="crm.crm_menu_root"]',
content: markup(_t('Ready to boost your sales? Let\'s have a look at your <b>Pipeline</b>.')),
tooltipPosition: 'bottom',
run: "click",
}, {
isActive: ["enterprise"],
trigger: '.o_app[data-menu-xmlid="crm.crm_menu_root"]',
content: markup(_t('Ready to boost your sales? Let\'s have a look at your <b>Pipeline</b>.')),
tooltipPosition: 'bottom',
run: "click",
},
{
trigger: ".o_opportunity_kanban .o_kanban_renderer",
},
{
trigger: '.o_opportunity_kanban .o-kanban-button-new',
content: markup(_t("<b>Create your first opportunity.</b>")),
tooltipPosition: 'bottom',
run: "click",
}, {
trigger: ".o_kanban_quick_create .o_field_widget[name='commercial_partner_id'] input",
content: markup(_t('<b>Write a few letters</b> to look for a company, or create a new one.')),
tooltipPosition: "top",
run: "edit Brandon Freeman",
}, {
isActive: ["auto"],
trigger: ".ui-menu-item > a:contains('Brandon Freeman')",
run: "click",
}, {
trigger: ".o_kanban_quick_create .o_field_widget[name='name'] input:value('Brandon Freeman')",
}, {
trigger: ".o_kanban_quick_create .o_kanban_add",
content: markup(_t("Now, <b>add your Opportunity</b> to your Pipeline.")),
tooltipPosition: "bottom",
run: "click",
},
{
trigger: ".o_opportunity_kanban .o_kanban_renderer",
},
{
trigger: ".o_opportunity_kanban:not(:has(.o_view_sample_data)) .o_kanban_group .o_kanban_record:last-of-type",
content: markup(_t("<b>Drag &amp; drop opportunities</b> between columns as you progress in your sales cycle.")),
tooltipPosition: "right",
run: "drag_and_drop(.o_opportunity_kanban .o_kanban_group:eq(2))",
},
{
trigger: ".o_opportunity_kanban .o_kanban_renderer",
},
{
// Choose the element that is not going to be moved by the previous step.
trigger: ".o_opportunity_kanban .o_kanban_group .o_kanban_record .o-mail-ActivityButton",
content: markup(_t("Looks like nothing is planned. :(<br><br><i>Tip: Schedule activities to keep track of everything you have to do!</i>")),
tooltipPosition: "bottom",
run: "click",
},
{
trigger: ".o_opportunity_kanban .o_kanban_renderer",
},
{
trigger: ".o-mail-ActivityListPopover button:contains(Schedule an activity)",
content: markup(_t("Let's <b>Schedule an Activity.</b>")),
tooltipPosition: "bottom",
run: "click",
}, {
trigger: '.modal-footer button[name="action_schedule_activities"]',
content: markup(_t("All set. Lets <b>Schedule</b> it.")),
tooltipPosition: "top", // dot NOT move to bottom, it would cause a resize flicker, see task-2476595
run: "click",
}, {
id: "drag_opportunity_to_won_step",
trigger: ".o_opportunity_kanban .o_kanban_record:last-of-type",
content: markup(_t("Drag your opportunity to <b>Won</b> when you get the deal. Congrats!")),
tooltipPosition: "right",
run: "drag_and_drop(.o_opportunity_kanban .o_kanban_group:eq(3))",
},
{
trigger: ".o_kanban_record",
content: _t("Lets have a look at an Opportunity."),
tooltipPosition: "right",
run: "click",
}, {
trigger: ".o_lead_opportunity_form .o_statusbar_status",
content: _t("You can make your opportunity advance through your pipeline from here."),
tooltipPosition: "bottom",
run: "click",
}, {
trigger: ".breadcrumb-item:not(.active):first",
content: _t("Click on the breadcrumb to go back to your Pipeline. Odoo will save all modifications as you navigate."),
tooltipPosition: "bottom",
run: "click .breadcrumb-item:not(.active):last",
}]});