Files
odoo_source/addons/web/views/webclient_templates.xml
T
Samuel Degueldre a1e7e3ef7e [FIX] web, *: tours correctly break when there are missing deps
*: im_livechat, website_livechat, website_slides

In c989ff3, the odoo module system has been changed so that it now
errors out when modules are defined but have missing dependencies and
cannot run. Unfortunately, tours are defined in a single bundle,
`assets_tests`, and this bundle is used everywhere tours need to run,
but some of these tours depend on modules that only exist in the backend
and others on modules that only exist in the frontend. We don't want to
break up the `assets_tests` bundle as this creates a poor developer
experience, and so the solution that was chosen at the time is that when
the `assets_tests` bundle is defined, we ignore all module dependency
errors.

This causes a problem however, which is that if a module dependency is
missing in production code, the page will be broken by the module error
(which is expected) but if the `assets_tests` are present, which is the
case when running tours and tests, then it won't, meaning the tours will
happily pass despite the application being broken, which is
unacceptable.

This commit fixes this issue by replacing the assets_test bundle by a
new bundle (`__assets_tests_call__`) within which all module dependency
errors are ignored, which lets dependency errors that are hapenning in
other bundles (ie in production code) happen even during the tests.

Because of this, this commit also fixes the dependency errors that
already existed but were previously silent:

- for im_livechat and website_livechat, the code was refactored to use
the standard mechanism that we use elsewhere to add data directly in the
page: we store the data in __session_info__, and the module that exposes
that data is always present, instead of having a module that's defined
conditionally, which causes issues when non-conditional modules depend
on it.
- in web, the `report_assets_common` bundle was used alongside
`assets_common` but without `assets_frontend` or `assets_backend`.
Reports do not need any js and it appears that it already had what it
needed as far as css is concerned except for one fontawesome override.
Code was changed so that the js from the bundle is not included and it
reports no longer use `assets_common`, the js part of the bundle is no
longer used.
- in website_slides, the `slide_embed_assets` bundle is used alongside
`assets_common` without using `assets_frontend` or `assets_backend`
which is required for `assets_common` to function, the approach here was
to simply take the files from `assets_common` and remove the files that
were causing issues. This bundle should be trimmed at some point, as it
contains way too many things that it does not need.

The file colors.js was also moved to core, as it isn't graph specific
and was causing dependency issues with a field that was importing it.
Fields shouldn't depend on files in specific views' directory.

closes odoo/odoo#104794

Related: odoo/enterprise#33909
Signed-off-by: Aaron Bohy (aab) <aab@odoo.com>
2022-11-17 15:59:16 +01:00

343 lines
17 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Call this template instead of "web.assets_tests" to have the proper conditional check -->
<template id="conditional_assets_tests" name="Tests Assets Bundle">
<t t-if="'tests' in debug or test_mode_enabled">
<!-- To allow all tests assets and tours to be in the same bundle, the assets_tests bundle ignores missing dependencies -->
<t t-call-assets="web.__assets_tests_call__" defer_load="True" />
</t>
</template>
<template id="web.layout" name="Web layout">&lt;!DOCTYPE html&gt;
<html t-att="html_data or {}">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<title t-esc="title or 'Odoo'"/>
<link type="image/x-icon" rel="shortcut icon" t-att-href="x_icon or '/web/static/img/favicon.ico'"/>
<script id="web.layout.odooscript" type="text/javascript">
var odoo = {
csrf_token: "<t t-nocache="The csrf token must always be up to date." t-esc="request.csrf_token(None)"/>",
debug: "<t t-esc="debug"/>",
};
</script>
<t t-out="head or ''"/>
</head>
<body t-att-class="body_classname">
<t t-out="0"/>
</body>
</html>
</template>
<template id="web.frontend_layout" name="Frontend Layout" inherit_id="web.layout" primary="True">
<xpath expr="//head/meta[last()]" position="after">
<meta name="viewport" content="width=device-width, initial-scale=1"/>
</xpath>
<xpath expr="//head/link[last()]" position="after">
<link rel="preload" href="/web/static/src/libs/fontawesome/fonts/fontawesome-webfont.woff2?v=4.7.0" as="font" crossorigin=""/>
<t t-call-assets="web.assets_frontend" t-js="false"/>
</xpath>
<xpath expr="//head/script[@id='web.layout.odooscript']" position="after">
<script t-nocache="Session information should always be up to date." type="text/javascript">
odoo.__session_info__ = <t t-out="json.dumps(request.env['ir.http'].get_frontend_session_info())"/>;
if (!/(^|;\s)tz=/.test(document.cookie)) {
const userTZ = Intl.DateTimeFormat().resolvedOptions().timeZone;
document.cookie = `tz=${userTZ}; path=/`;
}
</script>
<t t-call-assets="web.assets_frontend_minimal" t-css="false" defer_load="True"/>
<t t-call="web.conditional_assets_tests"/>
<t t-call-assets="web.assets_frontend_lazy" t-css="false" lazy_load="True"/>
</xpath>
<xpath expr="//t[@t-out='0']" position="replace">
<div id="wrapwrap" t-attf-class="#{pageName or ''}">
<header t-if="not no_header" id="top" data-anchor="true">
<img class="img-responsive d-block mx-auto"
t-attf-src="/web/binary/company_logo"
alt="Logo"/>
</header>
<main>
<t t-out="0"/>
</main>
<footer t-cache="no_footer,no_copyright" t-if="not no_footer" id="bottom" data-anchor="true" t-attf-class="bg-light o_footer">
<div id="footer"/>
<div t-if="not no_copyright" class="o_footer_copyright">
<div class="container py-3">
<div class="row">
<div class="col-sm text-center text-sm-start text-muted">
<span class="o_footer_copyright_name me-2">Copyright &amp;copy; <span t-field="res_company.name" itemprop="name">Company name</span></span>
</div>
<div class="col-sm text-center text-sm-end">
<t t-call="web.brand_promotion"/>
</div>
</div>
</div>
</div>
</footer>
</div>
</xpath>
</template>
<template id="brand_promotion_message" name="Brand Promotion Message">
<t t-set="odoo_logo">
<a target="_blank"
t-attf-href="http://www.odoo.com?utm_source=db&amp;utm_medium=#{_utm_medium}"
class="badge text-bg-light">
<img alt="Odoo"
src="/web/static/img/odoo_logo_tiny.png"
width="62" height="20"
style="width: auto; height: 1em; vertical-align: baseline;"/>
</a>
</t>
<t t-set="final_message">Powered by %s%s</t>
<t t-out="final_message % (odoo_logo, _message and ('- ' + _message) or '')"/>
</template>
<template id="brand_promotion" name="Brand Promotion">
<div class="o_brand_promotion">
<t t-call="web.brand_promotion_message">
<t t-set="_message"></t>
<t t-set="_utm_medium" t-valuef="portal"/>
</t>
</div>
</template>
<template id="web.login_layout" name="Login Layout">
<t t-call="web.frontend_layout">
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
<t t-set="body_classname" t-value="'bg-100'"/>
<t t-set="no_header" t-value="True"/>
<t t-set="no_footer" t-value="True"/>
<div class="container py-5">
<div t-attf-class="card border-0 mx-auto bg-100 {{login_card_classes}} o_database_list" style="max-width: 300px;">
<div class="card-body">
<div t-attf-class="text-center pb-3 border-bottom {{'mb-3' if form_small else 'mb-4'}}">
<img t-attf-src="/web/binary/company_logo{{ '?dbname='+db if db else '' }}" alt="Logo" style="max-height:120px; max-width: 100%; width:auto"/>
</div>
<t t-out="0"/>
<div class="text-center small mt-4 pt-3 border-top" t-if="not disable_footer">
<t t-if="not disable_database_manager">
<a class="border-end pe-2 me-1" href="/web/database/manager">Manage Databases</a>
</t>
<a href="https://www.odoo.com?utm_source=db&amp;utm_medium=auth" target="_blank">Powered by <span>Odoo</span></a>
</div>
</div>
</div>
</div>
</t>
</template>
<template id="web.login" name="Login">
<t t-call="web.login_layout">
<form class="oe_login_form" role="form" t-attf-action="/web/login" method="post" onsubmit="this.action = '/web/login' + location.hash">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="mb-3" t-if="databases and len(databases) &gt; 1">
<label for="db" class="col-form-label">Database</label>
<div t-attf-class="input-group {{'input-group-sm' if form_small else ''}}">
<input type="text" name="db" t-att-value="request.db" id="db" t-attf-class="form-control #{'form-control-sm' if form_small else ''}" required="required" readonly="readonly"/>
<a role="button" href="/web/database/selector" class="btn btn-secondary">Select <i class="fa fa-database" role="img" aria-label="Database" title="Database"></i></a>
</div>
</div>
<div class="mb-3 field-login">
<label for="login" class="form-label">Email</label>
<input type="text" placeholder="Email" name="login" t-att-value="login" id="login" t-attf-class="form-control #{'form-control-sm' if form_small else ''}" required="required" autofocus="autofocus" autocapitalize="off"/>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password</label>
<input type="password" placeholder="Password" name="password" id="password" t-attf-class="form-control #{'form-control-sm' if form_small else ''}" required="required" autocomplete="current-password" t-att-autofocus="'autofocus' if login else None" maxlength="4096"/>
</div>
<p class="alert alert-danger" t-if="error" role="alert">
<t t-esc="error"/>
</p>
<p class="alert alert-success" t-if="message" role="status">
<t t-esc="message"/>
</p>
<div t-attf-class="clearfix oe_login_buttons text-center gap-1 d-grid mb-1 {{'pt-2' if form_small else 'pt-3'}}">
<button type="submit" class="btn btn-primary">Log in</button>
<t t-if="debug">
<button type="submit" name="redirect" value="/web/become" class="btn btn-link btn-sm">Log in as superuser</button>
</t>
<div class="o_login_auth"/>
</div>
<input type="hidden" name="redirect" t-att-value="redirect"/>
</form>
</t>
</template>
<template id="web.login_successful" name="Login successful">
<t t-call="web.login_layout">
<div class="oe_login_form">
<p>
You are logged in.
</p>
<div t-attf-class="clearfix oe_login_buttons text-center mb-1 pt-3">
<a class="btn btn-primary btn-block" href="/web/session/logout">Log out</a>
</div>
</div>
</t>
</template>
<template id="web.test_helpers">
<t t-call-assets="web.tests_assets" t-js="False"/>
<style>
body {
position: relative; /* bootstrap-datepicker needs this */
}
body:not(.debug) .modal-backdrop, body:not(.debug) .modal, body:not(.debug) .ui-autocomplete {
opacity: 0 !important;
}
#qunit-testrunner-toolbar label {
font-weight: inherit;
margin-bottom: inherit;
}
#qunit-testrunner-toolbar input[type=text] {
width: inherit;
display: inherit;
}
</style>
<t t-call-assets="web.tests_assets" t-css="False"/>
</template>
<template id="web.qunit_suite">
<t t-call="web.layout">
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
<t t-set="title">Web Tests</t>
<t t-set="head">
<t t-call-assets="web.assets_common" t-js="false"/>
<t t-call-assets="web.assets_backend" t-js="false"/>
<t t-call-assets="web.tests_assets_common" t-css="false"/>
<t t-call-assets="web.assets_backend" t-css="false"/>
<t t-call="web.test_helpers"/>
<t t-call-assets="web.qunit_suite_tests" t-js="false"/>
<t t-call-assets="web.qunit_suite_tests" t-css="false"/>
</t>
<div id="qunit"/>
<div id="qunit-fixture"/>
</t>
</template>
<template id="web.qunit_mobile_suite">
<t t-call="web.layout">
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
<t t-set="title">Web Mobile Tests</t>
<t t-set="head">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<t t-call-assets="web.assets_common" t-js="false"/>
<t t-call-assets="web.assets_backend" t-js="false"/>
<t t-call-assets="web.tests_assets_common" t-css="false"/>
<t t-call-assets="web.assets_backend" t-css="false"/>
<t t-call="web.test_helpers"/>
<t t-call-assets="web.qunit_mobile_suite_tests" t-js="false"/>
<t t-call-assets="web.qunit_mobile_suite_tests" t-css="false"/>
</t>
<div id="qunit"/>
<div id="qunit-fixture"/>
</t>
</template>
<template id="web.benchmark_suite">
<t t-call="web.layout">
<t t-set="html_data" t-value="{'style': 'height: 100%;'}"/>
<t t-set="title">Web Benchmarks</t>
<t t-set="head">
<script type="text/javascript" src="/web/static/lib/benchmarkjs/lodash.js"></script>
<script type="text/javascript" src="/web/static/lib/benchmarkjs/benchmark.js"></script>
<t t-call-assets="web.assets_common" t-js="false"/>
<t t-call-assets="web.assets_backend" t-js="false"/>
<t t-call-assets="web.assets_common" t-css="false"/>
<t t-call-assets="web.assets_backend" t-css="false"/>
<t t-call="web.test_helpers"/>
<script type="text/javascript">
QUnit.config.hidepassed = false;
</script>
<style>
body:not(.debug) .modal-backdrop, body:not(.debug) .modal, body:not(.debug) .ui-autocomplete {
opacity: 0 !important;
}
#qunit-testrunner-toolbar label {
font-weight: inherit;
margin-bottom: inherit;
}
#qunit-testrunner-toolbar input[type=text] {
width: inherit;
display: inherit;
}
</style>
<script type="text/javascript" src="/web/static/tests/views/list_benchmarks.js"></script>
<script type="text/javascript" src="/web/static/tests/views/kanban_benchmarks.js"></script>
<script type="text/javascript" src="/web/static/tests/views/form_benchmarks.js"></script>
</t>
<div id="qunit"/>
<div id="qunit-fixture"/>
</t>
</template>
<template id="web.webclient_bootstrap">
<t t-call="web.layout">
<t t-set="head_web">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
<!-- Chrome, Firefox OS and Opera -->
<meta name="theme-color" content="#875A7B"/>
<link rel="icon" sizes="192x192" href="/web/static/img/mobile-icons/android-192x192.png"/>
<!-- iOS Safari -->
<meta name="apple-mobile-web-app-capable" content="yes"/>
<meta name="apple-mobile-web-app-status-bar-style" content="black"/>
<link rel="apple-touch-icon" href="/web/static/img/mobile-icons/apple-152x152.png"/>
<!-- Windows Phone -->
<meta name="msapplication-navbutton-color" content="#875A7B"/>
<meta name="msapplication-TileColor" content="#875A7B"/>
<meta name="msapplication-TileImage" content="/web/static/img/mobile-icons/windows-144x144.png"/>
<script type="text/javascript">
odoo.__session_info__ = <t t-out="json.dumps(session_info)"/>;
odoo.reloadMenus = () => fetch(`/web/webclient/load_menus/${odoo.__session_info__.cache_hashes.load_menus}`).then(res => res.json());
odoo.loadMenusPromise = odoo.reloadMenus();
// Block to avoid leaking variables in the script scope
{
const { user_context, cache_hashes } = odoo.__session_info__;
// Prefetch translations to speedup webclient. This is done in JS because link rel="prefetch"
// is not yet supported on safari.
fetch(`/web/webclient/translations/${cache_hashes.translations}?lang=${user_context.lang}`);
}
</script>
<t t-if="request.httprequest.cookies.get('color_scheme') == 'dark'">
<t t-call-assets="web.dark_mode_assets_common" t-js="false"/>
<t t-call-assets="web.dark_mode_assets_backend" t-js="false"/>
</t>
<t t-else="">
<t t-call-assets="web.assets_common" t-js="false"/>
<t t-call-assets="web.assets_backend" t-js="false"/>
</t>
<t t-call-assets="web.assets_common" t-css="false"/>
<t t-call-assets="web.assets_backend" t-css="false"/>
<t t-call-assets="web.assets_backend_prod_only" t-css="false"/>
<t t-call="web.conditional_assets_tests"/>
</t>
<t t-set="head" t-value="head_web + (head or '')"/>
<t t-set="body_classname" t-value="'o_web_client'"/>
</t>
</template>
</odoo>