Extending the desk client side scripting

Hi all. I’m currently trying to extend the client side script of ERPNext in terms of adding functionality to the Navbar. This is theoretically doable by adding your action to the list of actions in the NavBar Settings Single. The issue I’m having is adding functions to call as an action. Is there anybody who has had any success in doing anything similar? Below is my relevant code:

apps/eskill_custom/eskill_custom/public/js/utils/price_lookup.js

frappe.provide("eskill_custom");

eskill_custom.price_dialog = function () {
    document.getElementById("body").innerHTML += "<div style='position: fixed; bottom: 15mm;'>Hi " + frappe.session.user_fullname + "</div>";
};

I then reference the file in my apps hook.py:

app_include_js = [
	"/assets/eskill_custom/js/utils/price_lookup.js",
]

All of this matches the implementation of frappe.ui.toolbar as far as I have been able to ascertain however, the method is not available from the console. Unfortunately, there is no documentation that I can find regarding extending ERPNext in this way (I have made numerous other changes including creating new DocTypes, customizing existing ones, creating reports, and scheduling tasks). Thank you in advance!

@archais You can add an icon to the toolbar directly using the following code:

$('header.navbar > .container > .navbar-collapse > ul').prepend(`
    <li id="your-id" class="nav-item dropdown dropdown-notifications dropdown-mobile" title="{{ _('Your Title') }}">
        // Your Icon
    </li>
`);
$('#your-id').on('click', function() {
    // Your action code
});

Hi @kid1194. Thanks for your input, I’ve tried replacing my code in the mentioned price_lookup.js file with your sample code however, it still has no effect. Is there something that you have to do other than listing the asset path under the app_include_js array?

@archais For that, please check how I’m doing it in my plugin, link posted below.

  1. For the hooks.py file:
  • At the top, add:
from . import __version__ as app_version
from frappe import __version__ as frappe_version
  • for the include part, add the files like:
app_include_js = [
    'filename.bundle.js'
] if is_frappe_above_v13 else [
'/assets/plugin_name/js/filename.js'
]
  1. For the js file, add .bundle.js to the file name like filename.bundle.js

  2. Add a build.json file in your public directory and it’s content should be something like:

{
  "js/filename.js": ["public/js/filename.bundle.js"]
}
  1. If you need to use a js file in another inside your public directory, use the import & from attributes like:
import {function_name} from './utils/filename.js';
// or
import {class_name} from './utils/filename.js';
// or
import {
    function_name_1,
    function_name_2
} from './utils/filename.js';
// or
import {
    class_name,
    function_name
} from './utils';

But of you want to use your plugin inside a doctype js file, then add an access variable for your plugin to frappe variable from within your plugin js file, like frappe.plugin_name = something; and then in the doctype js file, use frappe.provide('frappe.plugin_name'); just in case it is not available.


2 Likes

Thank you so much @kid1194! It is now working, your help is greatly appreciated!

On the subject of using js files in another, I use frappe.require() this works for both other files in the public folder (such as the doctype.js files) and the js files for my own standard DocTypes. It was the making my code available in general to the site for the sake of extending the interface that was my major hiccup.