Problem or unprovided features:
-
The native Odoo community version 16 provide a unify Settings page view for addons modules, some time we want customize the left side menu item icon in the view, but it is not easy todo since the native code not provide relative interface yet. check issue: allow dynamic icon setting on configuration views
- #odoo Odoo 16 implement the Setting panel/form use compiler solution, accurate source code file is : ./addons/web/static/src/webclient/settings_form_view/settings_form_compiler.js
- the key step function code bellows:
function getAppIconUrl(module) {
return module === "general_settings"
? "/base/static/description/settings.png"
: "/" + module + "/static/description/icon.png";
}
the code above hard code that seem can not be customized and extends unless modify the original js code directly ❓❓❓
-
Solution
- brief:
- in this article we show a solution that inject new logic code into exist original code make the Setting view menu icons can be customized 🔨
- original logic workflow :
- while odoo frontend init (load web html page), workflow will add settings_form_view to registry.category("views") with key 'base_settings',
- the 'base_settings' use to render the Setting_page view .
- entry js file: addons/web/static/src/webclient/settings_form_view/settings_form_view.js
- it declare const value 'settingsFormView' which collect MVC classes for render Settings page .
export const settingsFormView = { ... Model: SettingsRelationalModel, ControlPanel: ControlPanel, Controller: SettingsFormController, Compiler: SettingsFormCompiler, // <--- this class is key point Renderer: SettingsFormRenderer, } registry.category("views").add("base_settings", settingsFormView);
- the class SettingsFormCompiler contains a property 'compilers' which is array that keep all relative compilers,
- the setting tab area (which contains the left side module menus ) was generate by the function compileSettingsPage(el, params) , so then what we can do is replace the exist inner function logic ~
steps:
- 1💡 find the exist settingsFormView.
since the settingsFormView was register in category 'views', the category is inherit from EventBus, EventBus mechanism is Observer pattern that can use to listener 'UPDATE' event while a view class was add into current runtime session, so hook code bellows:
const viewRegistry = registry.category("views");
viewRegistry.on("UPDATE", null, function (...args) {
console.log(...args);
const {operation,key,value} = args[0];
if (operation === 'add' && 'base_settings' === key){
console.log('⚒️ inject base_settings, key?, value?', key, value);
on_hook(value);
}
});
function on_hook(settingsFormView){
console.log('⚒️ onHook',settingsFormView)
}
start running the frontend code ( launcher Odoo python server, open web browser, navigate to odoo http entry point ), we use console check the log.
the console logout the class view 'settingsFormView' , most like bellows:
you see that is easy to intercept any view class that was defined base on owl framework❗️ ✅
the settingsFormView use to render the setting page in Odoo, the attribute 'Compiler' is the class 'SettingsFormCompiler' ('defined in file: settings_form_compiler.js')
- now we got the target : settingsFormView, next step 🔨 it, we need redefine the attribute 'Compiler' of the value settingsFormView with new class SetingCustomizeAbleCompiler
function on_hook(settingsFormView){
console.log('⚒️ onHook',settingsFormView)
const settingsFormCompiler = settingsFormView.Compiler;
if (settingsFormCompiler){
settingsFormView.Compiler = SetingCustomizeAbleCompiler;
return ;
}
}
- 2💡 override class SettingsFormCompiler apply with new log - We declare new class CustomizeAbleSettingsFormCompiler bellows
class CustomizeAbleSettingsFormCompiler extends SettingsFormCompiler {
setup() {
super.setup();
console.debug('inherited, this?', this);
const list = this.compilers;
for (let index = 0; index < list.length; index++) {
const item = list[index];
//match to: { selector: "div.settings", fn: compileSettingsPage },
if (item.selector === "div.settings"){
const original_hanlder = item.fn;
item.fn = compileSettingsPage; // assgin with new logic handler ~
}
}
}
}
notice above code, we only need hack the selector 'div.settings' , because the routine duty to generate the 'settings_tab' view that render the left side menu area, the function compileSettingsPage should be copy from original source code.
key step to make the menu icon can be configuration :
```
//@ modify logic here
function getAppIconUrl(module) {
console.log('⚒️ getAppIconUrl, module?', module)
// apply new logic
let value = getMenuIcon(module);
if (value) {
return value;
}
// continue old logic
return module === "general_settings"
? "/base/static/description/settings.png"
: "/" + module + "/static/description/icon.png";
}
function getMenuIcon(name){
if (name === 'purchase'){
return '/myModule/static/src/icon/purchase.png'
}
if (name === 'stock'){
return '/myModule/static/src/icon/stock.png'
}
// add more configuration here
return null;
}
```
3💡 finally run see the update
- if lucky then the left side menu icon was updated as expectation:
--
Conclusion
- Odoo offered a great data driver framework for ERP system, that is rapid development even low code solution, in this article we give a tips for customize the SettingView, the idea also can apply to other even whole page view in frontend development of owl.
- Hope this is helpful, if you have more better idea or suggestion, feel free leave comment or contact with us .
Happy coding and fun 👏
Top comments (0)