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
32 changes: 23 additions & 9 deletions web_theme_classic/README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

=================
Web Theme Classic
=================
Expand All @@ -17,7 +13,7 @@ Web Theme Classic
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github
Expand All @@ -32,15 +28,15 @@ Web Theme Classic

|badge1| |badge2| |badge3| |badge4| |badge5|

This module extend the Odoo Community Edition ``web`` module to improve
visibility of form view.
This module extends the Odoo Community Edition ``web`` module to improve
the visibility of input fields.

**Rational:** Since Odoo V17, the design is very pure. That's great, but
it generates some problem for users :

- Fields are not identifiable. (we can not know exactly where there are
- Fields are not identifiable. (we can not know exactly where they are
until you hover over them with the cursor)
- there is no indication for the required fields until trying to save
- There is no indication for the required fields until trying to save
(or exit the screen)

In a way, this module restores the form display of version 15, but
Expand All @@ -62,6 +58,24 @@ preserving the "save on the fly" new feature.
.. contents::
:local:

Configuration
=============

This module allows each user to choose whether they would like input
fields to be displayed the "classic" way or the new, standard way (as if
this module were not installed)

To do this you can either:

- Check "Classic Theme Persistent" in user preferences. This will enable
the classic theme for that user across all devices.
- Check the "Classic Theme" toggle in the popover menu triggered bu
clicking on the user icon in the navbar. This toggle is only visible
when "Classic Theme Persistent" is disabled.

Please note that when disabling "Classic Theme Persistent" the style
will not change until the page is reloaded.

Bug Tracker
===========

Expand Down
1 change: 1 addition & 0 deletions web_theme_classic/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
7 changes: 7 additions & 0 deletions web_theme_classic/__manifest__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Copyright (C) 2022 - Today: GRAP (http://www.grap.coop)
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
# © 2025 Liam Noonan - Pyxiris
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

{
Expand All @@ -14,8 +15,14 @@
"depends": [
"web",
],
"data": [
"views/res_users_views.xml",
],
"assets": {
"web.assets_backend": [
"web_theme_classic/static/src/js/switch_theme.esm.js",
],
"web.assets_web": [
"/web_theme_classic/static/src/scss/web_theme_classic.scss",
],
"web.assets_web_dark": [
Expand Down
1 change: 1 addition & 0 deletions web_theme_classic/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import ir_http, res_users, res_users_settings
28 changes: 28 additions & 0 deletions web_theme_classic/models/ir_http.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# © 2022 Florian Kantelberg - initOS GmbH
# © 2025 Liam Noonan - Pyxiris
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import models
from odoo.http import request


class IrHttp(models.AbstractModel):
_inherit = "ir.http"

@classmethod
def _set_classic_theme(cls, response):
user = request.env.user
if user and user._is_internal():
existing_transient_theme = request.httprequest.cookies.get(
"transient_classic_theme_cookie"
)
persistent_theme = getattr(user, "persistent_classic_theme", None)
# Delete the cookie so that when persistent gets turned off the user
# will not be left wondering why nothing changed
if persistent_theme and existing_transient_theme:
response.delete_cookie("transient_classic_theme_cookie")

@classmethod
def _post_dispatch(cls, response):
cls._set_classic_theme(response)
return super()._post_dispatch(response)
31 changes: 31 additions & 0 deletions web_theme_classic/models/res_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# © 2022 Florian Kantelberg - initOS GmbH
# © 2025 Liam Noonan - Pyxiris
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResUsers(models.Model):
_inherit = "res.users"

persistent_classic_theme = fields.Boolean(
related="res_users_settings_id.persistent_classic_theme",
readonly=False,
string="Classic Theme Persistent",
help="This enables Classic Theme on this user's account across all devices. \n "
"Disabling it will will alow you to to use the toggle in the user burger menu "
"in the navbar to enable Classic Mode on a specific session/device \n"
"The toggle is not visible while Persistent Classic Theme is enabled",
)

@property
def SELF_READABLE_FIELDS(self):
return super().SELF_READABLE_FIELDS + [
"persistent_classic_theme",
]

@property
def SELF_WRITEABLE_FIELDS(self):
return super().SELF_WRITEABLE_FIELDS + [
"persistent_classic_theme",
]
12 changes: 12 additions & 0 deletions web_theme_classic/models/res_users_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# © 2026 Liam Noonan - Pyxiris
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import fields, models


class ResUsersSettings(models.Model):
_inherit = "res.users.settings"

# These fields should be here in order to be accessible via in js
# as user.settings.persistent_classic_theme
persistent_classic_theme = fields.Boolean(default=True)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: maybe add help for the note from the configure.md, something like: "When switching the theme all users need to reload the page to have a effect."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a pretty verbose tooltip defined in res_users.py, although it does not mention the need to reload. I'm hesitant to add this though as pressing "Save" from the view_users_form_simple_modif modal actually triggers a reload, so it is only in the context of view_users_form that this is relevant. Also, I think it is something that should be rather obvious to any user savvy enough to enable debug mode, which is necessary to see this option in the context of view_users_form in the first place.
If @legalsylvain thinks it is necessary too, I will add it

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ljmnoonan oh, clear!

7 changes: 7 additions & 0 deletions web_theme_classic/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
This module allows each user to choose whether they would like input fields to be displayed the "classic" way or the new, standard way (as if this module were not installed)

To do this you can either:
+ Check "Classic Theme Persistent" in user preferences. This will enable the classic theme for that user across all devices.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should write "Uncheck" since you enabled the theme by default if the conversation in the pr is right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ofc: nitpick

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should stay "check" as writing "uncheck" would necessitate inverting the whole sentence. It's kind of odd describing a feature by what it doesn't do when it is turned off. The next line describes behavior when unchecked too.

+ Check the "Classic Theme" toggle in the popover menu triggered bu clicking on the user icon in the navbar. This toggle is only visible when "Classic Theme Persistent" is disabled.

Please note that when disabling "Classic Theme Persistent" the style will not change until the page is reloaded.
8 changes: 4 additions & 4 deletions web_theme_classic/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
This module extend the Odoo Community Edition `web` module to improve
visibility of form view.
This module extends the Odoo Community Edition `web` module to improve
the visibility of input fields.

**Rational:** Since Odoo V17, the design is very pure. That's great, but
it generates some problem for users :

- Fields are not identifiable. (we can not know exactly
where there are until you hover over them with the cursor)
- there is no indication for the required fields until trying to save
where they are until you hover over them with the cursor)
- There is no indication for the required fields until trying to save
(or exit the screen)

In a way, this module restores the form display of version 15, but
Expand Down
59 changes: 35 additions & 24 deletions web_theme_classic/static/description/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils: https://docutils.sourceforge.io/" />
<title>README.rst</title>
<title>Web Theme Classic</title>
<style type="text/css">

/*
Expand Down Expand Up @@ -360,29 +360,24 @@
</style>
</head>
<body>
<div class="document">
<div class="document" id="web-theme-classic">
<h1 class="title">Web Theme Classic</h1>


<a class="reference external image-reference" href="https://odoo-community.org/get-involved?utm_source=readme">
<img alt="Odoo Community Association" src="https://odoo-community.org/readme-banner-image" />
</a>
<div class="section" id="web-theme-classic">
<h1>Web Theme Classic</h1>
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:27279023c56e7554295aea7c8e94ddad0c3cf9962ba5f11a6de4b8c1766e9e59
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/license-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/web/tree/18.0/web_theme_classic"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-18-0/web-18-0-web_theme_classic"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module extend the Odoo Community Edition <tt class="docutils literal">web</tt> module to improve
visibility of form view.</p>
<p><a class="reference external image-reference" href="https://odoo-community.org/page/development-status"><img alt="Beta" src="https://img.shields.io/badge/maturity-Beta-yellow.png" /></a> <a class="reference external image-reference" href="http://www.gnu.org/licenses/agpl-3.0-standalone.html"><img alt="License: AGPL-3" src="https://img.shields.io/badge/licence-AGPL--3-blue.png" /></a> <a class="reference external image-reference" href="https://github.com/OCA/web/tree/18.0/web_theme_classic"><img alt="OCA/web" src="https://img.shields.io/badge/github-OCA%2Fweb-lightgray.png?logo=github" /></a> <a class="reference external image-reference" href="https://translation.odoo-community.org/projects/web-18-0/web-18-0-web_theme_classic"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external image-reference" href="https://runboat.odoo-community.org/builds?repo=OCA/web&amp;target_branch=18.0"><img alt="Try me on Runboat" src="https://img.shields.io/badge/runboat-Try%20me-875A7B.png" /></a></p>
<p>This module extends the Odoo Community Edition <tt class="docutils literal">web</tt> module to improve
the visibility of input fields.</p>
<p><strong>Rational:</strong> Since Odoo V17, the design is very pure. That’s great, but
it generates some problem for users :</p>
<ul class="simple">
<li>Fields are not identifiable. (we can not know exactly where there are
<li>Fields are not identifiable. (we can not know exactly where they are
until you hover over them with the cursor)</li>
<li>there is no indication for the required fields until trying to save
<li>There is no indication for the required fields until trying to save
(or exit the screen)</li>
</ul>
<p>In a way, this module restores the form display of version 15, but
Expand All @@ -394,33 +389,50 @@ <h1>Web Theme Classic</h1>
<p><strong>Table of contents</strong></p>
<div class="contents local topic" id="contents">
<ul class="simple">
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-1">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-2">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-3">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-4">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-5">Maintainers</a></li>
<li><a class="reference internal" href="#configuration" id="toc-entry-1">Configuration</a></li>
<li><a class="reference internal" href="#bug-tracker" id="toc-entry-2">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="toc-entry-3">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="toc-entry-4">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="toc-entry-5">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="toc-entry-6">Maintainers</a></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="configuration">
<h1><a class="toc-backref" href="#toc-entry-1">Configuration</a></h1>
<p>This module allows each user to choose whether they would like input
fields to be displayed the “classic” way or the new, standard way (as if
this module were not installed)</p>
<p>To do this you can either:</p>
<ul class="simple">
<li>Check “Classic Theme Persistent” in user preferences. This will enable
the classic theme for that user across all devices.</li>
<li>Check the “Classic Theme” toggle in the popover menu triggered bu
clicking on the user icon in the navbar. This toggle is only visible
when “Classic Theme Persistent” is disabled.</li>
</ul>
<p>Please note that when disabling “Classic Theme Persistent” the style
will not change until the page is reloaded.</p>
</div>
<div class="section" id="bug-tracker">
<h2><a class="toc-backref" href="#toc-entry-1">Bug Tracker</a></h2>
<h1><a class="toc-backref" href="#toc-entry-2">Bug Tracker</a></h1>
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/web/issues">GitHub Issues</a>.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
<a class="reference external" href="https://github.com/OCA/web/issues/new?body=module:%20web_theme_classic%0Aversion:%2018.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p>
<p>Do not contact contributors directly about support or help with technical issues.</p>
</div>
<div class="section" id="credits">
<h2><a class="toc-backref" href="#toc-entry-2">Credits</a></h2>
<h1><a class="toc-backref" href="#toc-entry-3">Credits</a></h1>
<div class="section" id="authors">
<h3><a class="toc-backref" href="#toc-entry-3">Authors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-4">Authors</a></h2>
<ul class="simple">
<li>GRAP</li>
</ul>
</div>
<div class="section" id="contributors">
<h3><a class="toc-backref" href="#toc-entry-4">Contributors</a></h3>
<h2><a class="toc-backref" href="#toc-entry-5">Contributors</a></h2>
<ul class="simple">
<li>Sylvain LE GAL (<a class="reference external" href="https://www.twitter.com/legalsylvain">https://www.twitter.com/legalsylvain</a>)</li>
<li><a class="reference external" href="https://github.com/Pyxiris">Pyxiris</a><ul>
Expand All @@ -430,7 +442,7 @@ <h3><a class="toc-backref" href="#toc-entry-4">Contributors</a></h3>
</ul>
</div>
<div class="section" id="maintainers">
<h3><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h3>
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
Expand All @@ -445,6 +457,5 @@ <h3><a class="toc-backref" href="#toc-entry-5">Maintainers</a></h3>
</div>
</div>
</div>
</div>
</body>
</html>
62 changes: 62 additions & 0 deletions web_theme_classic/static/src/js/switch_theme.esm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// © 2022 Florian Kantelberg - initOS GmbH
// © 2025 Liam Noonan - Pyxiris
// License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

import {_t} from "@web/core/l10n/translation";
import {browser} from "@web/core/browser/browser";
import {cookie} from "@web/core/browser/cookie";
import {registry} from "@web/core/registry";
import {user} from "@web/core/user";

/**
* @param {import("@web/env").OdooEnv} env
*/
function classicThemeSwitchItem(env) {
return {
type: "switch",
id: "classic_theme.switch",
description: _t("Classic Theme"),
callback: () => {
env.services.classic_theme.switchTheme();
},
isChecked: cookie.get("transient_classic_theme_cookie") === "classic",
sequence: 43,
};
}

export const classicThemeService = {
dependencies: ["ui"],

start(env, {ui}) {
// Apply theme on load
if (
cookie.get("transient_classic_theme_cookie") === "classic" ||
user.settings.persistent_classic_theme
) {
document.body.classList.add("classic-theme");
}

if (!user.settings.persistent_classic_theme) {
registry
.category("user_menuitems")
.add("classic_theme.switch", classicThemeSwitchItem);
}

return {
async switchTheme() {
const newValue =
cookie.get("transient_classic_theme_cookie") === "classic"
? "pure"
: "classic";
cookie.set("transient_classic_theme_cookie", newValue);
document.body.classList.toggle("classic-theme", newValue === "classic");

// We do not actually need a reload, but it does get rid of some style glitches
ui.block();
browser.location.reload();
},
};
},
};

registry.category("services").add("classic_theme", classicThemeService);
Loading