[Guide] Modifying Frappe app navbar

Steps

Include js to app

Create a .js file your_app/public/js/override_desk.js

Add file to hook.py

# hook.py

app_include_js = [
    "/assets/your_app/js/override_desk.js",
]

Overriding component

In my case I want to replace navbar so I add frappe.templates['navbar'] to override_desk.js (which we just create)

// your_app/public/js/override_desk.js

frappe.templates['navbar'] = `
<div>
  <div>Hello Sir</div>
  <!-- This part is for awesomplete (desk will throw error if it's missing)-->
  <div class="input-group search-bar text-muted hidden">
    <input
      id="navbar-search"
      type="text"
      class="form-control"
      placeholder="{%= __('Search or type a command ({0})', [frappe.utils.is_mac() ? '⌘ + G' : 'Ctrl + G']) %}"
      aria-haspopup="true"
    >
    <span class="search-icon">
      <svg class="icon icon-sm"><use href="#icon-search"></use></svg>
    </span>
  </div>
</div>
`

Reload

Run bench build to build asset then do hard reload on browser.

You should see change when reload desk.


Research Notes

These are finding when I tried to find the solution, which might be useful to modified the app in another case.

/app is just another www page

/app/* directory is actually just another www page.

It use /www/app.py to build context then pass those context to /www/app.html.

In /www/app.html file you would find a simple html

<div class="main-section">
	<header></header>
	<div id="body"></div>
	<footer></footer>
</div>

The building the page part are reside in JavaScript side of thing.

Modified templates

You could easily override www or templates/pages of frappe by just create a file there.

Using hook.py

You could specify base_template or base_template_map to update base template.

8 Likes

add other data in navbar ? how like FY fical year add in navbar

any updates on this ?

From frappe “chat” module i need to override some js fuctions in my custom app.

For example override the below class fuction:

import { create_private_room } from ‘./chat_utils’;

export default class ChatAddRoom {
constructor(opts) {
this.user = opts.user;
this.users_list = […frappe.user.get_emails(), ‘Administrator’];
this.user_email = opts.user_email;
this.users_list = this.users_list.filter(function (user) {
return user != opts.user_email;
});
this.setup();
}

async setup() {
this.add_room_dialog = new frappe.ui.Dialog({
title: __(‘Jobtemp Chat Room’),
fields: [
{
label: __(‘Room Type’),
fieldname: ‘type’,
fieldtype: ‘Select’,
options: [‘Group’, ‘Direct’],
default: ‘Group’,
onchange: () => {
const type = this.add_room_dialog.get_value(‘type’);
const is_group = type === ‘Group’;
this.add_room_dialog.set_df_property(‘room_name’, ‘reqd’, is_group);
this.add_room_dialog.set_df_property(‘users’, ‘reqd’, is_group);
this.add_room_dialog.set_df_property(‘user’, ‘reqd’, !is_group);
},
reqd: true,
},
{
label: __(‘Room Name’),
fieldname: ‘room_name’,
fieldtype: ‘Data’,
depends_on: “eval:doc.type == ‘Group’”,
reqd: true,
},
{
label: __(‘Users’),
fieldname: ‘users’,
fieldtype: ‘MultiSelectPills’,
options: this.users_list,
depends_on: “eval:doc.type == ‘Group’”,
reqd: true,
},
{
label: __(‘User’),
fieldname: ‘user’,
fieldtype: ‘Link’,
options: ‘User’,
depends_on: “eval:doc.type == ‘Direct’”,
},
],
action: {
primary: {
label: __(‘Create’),
onsubmit: (values) => {
let users = this.add_room_dialog.fields_dict.users.get_values();
let room_name = values.room_name;
if (values.type === ‘Direct’) {
users = [values.user];
room_name = ‘Direct Room’;
}
this.handle_room_creation(room_name, users, values.type);
this.add_room_dialog.hide();
},
},
},
});
}

show() {
this.add_room_dialog.show();
}

async handle_room_creation(room_name, users, type) {
try {
await create_private_room(room_name, users, type);
this.add_room_dialog.clear();
} catch (error) {
//pass
}
}
}

located at: /home/xadmin/frappe-bench/apps/chat/chat/public/js/components/chat_add_room.js

I made too many attempts but not able to do. Immediate response would be appreciated!